import { eq, and, sql } from 'drizzle-orm'; import { db } from '@/db'; import { promptUrlCache } from '@banatie/database'; import type { PromptUrlCacheEntry, NewPromptUrlCacheEntry } from '@/types/models'; import { computeSHA256 } from '@/utils/helpers'; export class PromptCacheService { /** * Compute SHA-256 hash of prompt for cache lookup */ computePromptHash(prompt: string): string { return computeSHA256(prompt); } /** * Check if prompt exists in cache for a project */ async getCachedEntry( promptHash: string, projectId: string ): Promise { const entry = await db.query.promptUrlCache.findFirst({ where: and( eq(promptUrlCache.promptHash, promptHash), eq(promptUrlCache.projectId, projectId) ), }); return entry || null; } /** * Create a new cache entry */ async createCacheEntry(data: NewPromptUrlCacheEntry): Promise { const [entry] = await db.insert(promptUrlCache).values(data).returning(); if (!entry) { throw new Error('Failed to create cache entry'); } return entry; } /** * Update hit count and last hit time for a cache entry */ async recordCacheHit(id: string): Promise { await db .update(promptUrlCache) .set({ hitCount: sql`${promptUrlCache.hitCount} + 1`, lastHitAt: new Date(), }) .where(eq(promptUrlCache.id, id)); } /** * Get cache statistics for a project */ async getCacheStats(projectId: string): Promise<{ totalEntries: number; totalHits: number; avgHitCount: number; }> { const entries = await db.query.promptUrlCache.findMany({ where: eq(promptUrlCache.projectId, projectId), }); const totalEntries = entries.length; const totalHits = entries.reduce((sum, entry) => sum + entry.hitCount, 0); const avgHitCount = totalEntries > 0 ? totalHits / totalEntries : 0; return { totalEntries, totalHits, avgHitCount, }; } /** * Clear old cache entries (can be called periodically) */ async clearOldEntries(daysOld: number): Promise { const cutoffDate = new Date(); cutoffDate.setDate(cutoffDate.getDate() - daysOld); const result = await db .delete(promptUrlCache) .where( and( eq(promptUrlCache.hitCount, 0), // Only delete entries with 0 hits that are old ) ) .returning(); return result.length; } }