This repository has no description
1import { db } from "../../../libs/db";
2import { users as usersTable, takes as takesTable } from "../../../libs/schema";
3import { handleApiError } from "../../../libs/apiError";
4import { eq, sql } from "drizzle-orm";
5
6// Time data cache to reduce database queries
7const timeCache = new Map<
8 string,
9 {
10 data: {
11 userId: string;
12 totalTakesTime: number;
13 dailyStats: { date: string; seconds: number }[];
14 };
15 timestamp: number;
16 }
17>();
18const TIME_CACHE_TTL = 5 * 60 * 1000; // 5 minutes cache TTL
19
20export async function time(url: URL): Promise<Response> {
21 try {
22 const userId = url.searchParams.get("user");
23
24 if (!userId) {
25 return new Response(
26 JSON.stringify({
27 error: "User ID is required",
28 }),
29 {
30 headers: {
31 "Content-Type": "application/json",
32 },
33 status: 400,
34 },
35 );
36 }
37
38 // Check cache before database query
39 const cacheKey = `time_${userId}`;
40 const cached = timeCache.get(cacheKey);
41 if (cached && Date.now() - cached.timestamp < TIME_CACHE_TTL) {
42 return new Response(JSON.stringify(cached.data), {
43 headers: {
44 "Content-Type": "application/json",
45 },
46 });
47 }
48
49 // Get user's total takes time from the database
50 const userData = await db
51 .select({
52 totalTakesTime: usersTable.totalTakesTime,
53 })
54 .from(usersTable)
55 .where(eq(usersTable.id, userId))
56 .limit(1);
57
58 if (!userData[0]) {
59 return new Response(
60 JSON.stringify({
61 error: "User not found",
62 }),
63 {
64 headers: {
65 "Content-Type": "application/json",
66 },
67 status: 404,
68 },
69 );
70 }
71
72 // Get time logged per day
73 const dailyStats = await db
74 .select({
75 date: sql<string>`DATE(${takesTable.createdAt})`,
76 dailyTotal: sql<number>`SUM(${takesTable.elapsedTime})`,
77 })
78 .from(takesTable)
79 .where(eq(takesTable.userId, userId))
80 .groupBy(sql`DATE(${takesTable.createdAt})`)
81 .orderBy(sql`DATE(${takesTable.createdAt}) DESC`);
82
83 const responseData = {
84 userId,
85 totalTakesTime: userData[0].totalTakesTime || 0,
86 dailyStats: dailyStats.map((day) => ({
87 date: day.date,
88 seconds: day.dailyTotal,
89 })),
90 };
91
92 // Store in cache
93 timeCache.set(cacheKey, {
94 data: responseData,
95 timestamp: Date.now(),
96 });
97
98 return new Response(JSON.stringify(responseData), {
99 headers: {
100 "Content-Type": "application/json",
101 },
102 });
103 } catch (error) {
104 return handleApiError(error, "userTime");
105 }
106}