|
1 | 1 | import { chQuery } from '@databuddy/db'; |
| 2 | +import { createDrizzleCache, redis } from '@databuddy/redis'; |
2 | 3 | import { TRPCError } from '@trpc/server'; |
3 | 4 | import { z } from 'zod/v4'; |
4 | 5 | import { logger } from '../lib/logger'; |
5 | 6 | import { createTRPCRouter, protectedProcedure } from '../trpc'; |
6 | 7 | import { authorizeWebsiteAccess } from '../utils/auth'; |
7 | 8 |
|
| 9 | +const drizzleCache = createDrizzleCache({ redis, namespace: 'autocomplete' }); |
| 10 | + |
| 11 | +const CACHE_TTL = 1800; |
| 12 | + |
8 | 13 | const analyticsDateRangeSchema = z.object({ |
9 | 14 | websiteId: z.string(), |
10 | 15 | startDate: z.string().optional(), |
@@ -136,34 +141,40 @@ const categorizeAutocompleteResults = ( |
136 | 141 | export const autocompleteRouter = createTRPCRouter({ |
137 | 142 | get: protectedProcedure |
138 | 143 | .input(analyticsDateRangeSchema) |
139 | | - .query(async ({ ctx, input }) => { |
140 | | - const website = await authorizeWebsiteAccess( |
141 | | - ctx, |
142 | | - input.websiteId, |
143 | | - 'read' |
144 | | - ); |
| 144 | + .query(({ ctx, input }) => { |
145 | 145 | const { startDate, endDate } = |
146 | 146 | input.startDate && input.endDate |
147 | 147 | ? { startDate: input.startDate, endDate: input.endDate } |
148 | 148 | : getDefaultDateRange(); |
149 | | - const params = { websiteId: website.id, startDate, endDate }; |
150 | 149 |
|
151 | | - try { |
152 | | - const results = await chQuery<{ |
153 | | - category: string; |
154 | | - value: string; |
155 | | - }>(getAutocompleteQuery(), params); |
| 150 | + const cacheKey = `autocomplete:${input.websiteId}:${startDate}:${endDate}`; |
| 151 | + |
| 152 | + return drizzleCache.withCache({ |
| 153 | + key: cacheKey, |
| 154 | + ttl: CACHE_TTL, |
| 155 | + tables: ['websites'], |
| 156 | + queryFn: async () => { |
| 157 | + await authorizeWebsiteAccess(ctx, input.websiteId, 'read'); |
| 158 | + const params = { websiteId: input.websiteId, startDate, endDate }; |
| 159 | + |
| 160 | + try { |
| 161 | + const results = await chQuery<{ |
| 162 | + category: string; |
| 163 | + value: string; |
| 164 | + }>(getAutocompleteQuery(), params); |
156 | 165 |
|
157 | | - return categorizeAutocompleteResults(results); |
158 | | - } catch (error) { |
159 | | - logger.error('Failed to fetch autocomplete data', { |
160 | | - error: error instanceof Error ? error.message : String(error), |
161 | | - websiteId: website.id, |
162 | | - }); |
163 | | - throw new TRPCError({ |
164 | | - code: 'INTERNAL_SERVER_ERROR', |
165 | | - message: 'Failed to fetch autocomplete data', |
166 | | - }); |
167 | | - } |
| 166 | + return categorizeAutocompleteResults(results); |
| 167 | + } catch (error) { |
| 168 | + logger.error('Failed to fetch autocomplete data', { |
| 169 | + error: error instanceof Error ? error.message : String(error), |
| 170 | + websiteId: input.websiteId, |
| 171 | + }); |
| 172 | + throw new TRPCError({ |
| 173 | + code: 'INTERNAL_SERVER_ERROR', |
| 174 | + message: 'Failed to fetch autocomplete data', |
| 175 | + }); |
| 176 | + } |
| 177 | + }, |
| 178 | + }); |
168 | 179 | }), |
169 | 180 | }); |
0 commit comments