This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 3.9 kB View raw
1import { eq, desc } from "drizzle-orm"; 2import { db } from "../../../libs/db"; 3import { takes as takesTable, users as usersTable } from "../../../libs/schema"; 4import { handleApiError } from "../../../libs/apiError"; 5import { userService } from "../../../libs/cachet"; 6 7export type RecentTake = { 8 id: string; 9 userId: string; 10 notes: string; 11 createdAt: Date; 12 mediaUrls: string[]; 13 /* elapsed time in seconds */ 14 elapsedTime: number; 15 project: string; 16 /* total time in seconds */ 17 totalTakesTime: number; 18 userName?: string; // Add userName field 19}; 20 21// Recent takes cache to reduce database queries 22const takesCache = new Map<string, { data: RecentTake[]; timestamp: number }>(); 23const TAKES_CACHE_TTL = 30 * 1000; // 30 seconds cache TTL - shorter since takes change frequently 24 25export async function recentTakes(url: URL): Promise<Response> { 26 try { 27 const userId = url.searchParams.get("user"); 28 29 // Check cache before querying database 30 const cacheKey = userId || "all_takes"; 31 const cached = takesCache.get(cacheKey); 32 if (cached && Date.now() - cached.timestamp < TAKES_CACHE_TTL) { 33 return new Response( 34 JSON.stringify({ 35 takes: cached.data, 36 }), 37 { 38 headers: { 39 "Content-Type": "application/json", 40 }, 41 }, 42 ); 43 } 44 45 if (userId) { 46 // Verify user exists if userId provided 47 const user = await db 48 .select() 49 .from(usersTable) 50 .where(eq(usersTable.id, userId)) 51 .limit(1); 52 53 if (user.length === 0) { 54 return new Response( 55 JSON.stringify({ 56 error: "User not found", 57 takes: [], 58 }), 59 { 60 status: 404, 61 headers: { 62 "Content-Type": "application/json", 63 }, 64 }, 65 ); 66 } 67 } 68 69 // Use a JOIN query to get takes and user data in a single operation 70 const takesWithUserData = await db 71 .select({ 72 take: { 73 id: takesTable.id, 74 userId: takesTable.userId, 75 notes: takesTable.notes, 76 createdAt: takesTable.createdAt, 77 media: takesTable.media, 78 elapsedTime: takesTable.elapsedTime, 79 }, 80 user: { 81 projectName: usersTable.projectName, 82 totalTakesTime: usersTable.totalTakesTime, 83 }, 84 }) 85 .from(takesTable) 86 .leftJoin(usersTable, eq(takesTable.userId, usersTable.id)) 87 .where(userId ? eq(takesTable.userId, userId) : undefined) 88 .orderBy(desc(takesTable.createdAt)) 89 .limit(40); 90 91 if (takesWithUserData.length === 0) { 92 return new Response( 93 JSON.stringify({ 94 takes: [], 95 }), 96 { 97 headers: { 98 "Content-Type": "application/json", 99 }, 100 }, 101 ); 102 } 103 104 // Get unique user IDs 105 const userIds = [ 106 ...new Set(takesWithUserData.map((item) => item.take.userId)), 107 ]; 108 109 // Fetch all user names from shared user service 110 const userNamesPromises = userIds.map((id) => 111 userService.getUserName(id), 112 ); 113 const userNames = await Promise.all(userNamesPromises); 114 115 // Create a map of user names 116 const userNameMap: Record<string, string> = {}; 117 userIds.forEach((id, index) => { 118 userNameMap[id] = userNames[index] || "unknown"; 119 }); 120 121 // Map the joined results to the expected format 122 const takes: RecentTake[] = takesWithUserData.map((item) => ({ 123 id: item.take.id, 124 userId: item.take.userId, 125 notes: item.take.notes, 126 createdAt: new Date(item.take.createdAt), 127 mediaUrls: item.take.media ? JSON.parse(item.take.media) : [], 128 elapsedTime: item.take.elapsedTime, 129 project: item.user?.projectName || "unknown project", 130 totalTakesTime: item.user?.totalTakesTime || item.take.elapsedTime, 131 userName: userNameMap[item.take.userId] || "Unknown User", 132 })); 133 134 // Store results in cache 135 takesCache.set(cacheKey, { 136 data: takes, 137 timestamp: Date.now(), 138 }); 139 140 return new Response( 141 JSON.stringify({ 142 takes, 143 }), 144 { 145 headers: { 146 "Content-Type": "application/json", 147 }, 148 }, 149 ); 150 } catch (error) { 151 return handleApiError(error, "recentTakes"); 152 } 153}