| 179 | } |
| 180 | |
| 181 | function cases(samplePubkey: Buffer): BenchmarkCase[] { |
| 182 | const now = Math.floor(Date.now() / 1000) |
| 183 | const sevenDaysAgo = now - 7 * 86400 |
| 184 | return [ |
| 185 | { |
| 186 | // Shape matches EventRepository.findByFilters exactly. |
| 187 | name: 'REQ authors+kind ORDER BY created_at DESC LIMIT 500', |
| 188 | sql: `SELECT event_id FROM events |
| 189 | WHERE event_pubkey = $1 AND event_kind = ANY($2::int[]) |
| 190 | ORDER BY event_created_at DESC, event_id ASC LIMIT 500`, |
| 191 | params: [samplePubkey, [1]], |
| 192 | }, |
| 193 | { |
| 194 | // This is the only hot path that filters on deleted_at in production. |
| 195 | name: 'hasActiveRequestToVanish (pubkey + kind=62)', |
| 196 | sql: `SELECT event_id FROM events |
| 197 | WHERE event_pubkey = $1 AND event_kind = 62 AND deleted_at IS NULL LIMIT 1`, |
| 198 | params: [samplePubkey], |
| 199 | }, |
| 200 | { |
| 201 | name: 'Purge scan: soft-deleted rows', |
| 202 | sql: `SELECT event_id FROM events WHERE deleted_at IS NOT NULL LIMIT 500`, |
| 203 | params: [], |
| 204 | }, |
| 205 | { |
| 206 | // Shape matches InvoiceRepository.findPendingInvoices exactly. |
| 207 | name: 'findPendingInvoices ORDER BY created_at', |
| 208 | sql: `SELECT id FROM invoices WHERE status = 'pending' ORDER BY created_at ASC OFFSET 0 LIMIT 500`, |
| 209 | params: [], |
| 210 | }, |
| 211 | { |
| 212 | name: 'REQ kind + time range ORDER BY created_at DESC LIMIT 500', |
| 213 | sql: `SELECT event_id FROM events |
| 214 | WHERE event_kind = 1 AND event_created_at BETWEEN $1 AND $2 |
| 215 | ORDER BY event_created_at DESC, event_id ASC LIMIT 500`, |
| 216 | params: [sevenDaysAgo, now], |
| 217 | }, |
| 218 | ] |
| 219 | } |
| 220 | |
| 221 | async function explain(sql: string, params: unknown[]): Promise<ExplainResult> { |
| 222 | const { rows } = await client.query<{ 'QUERY PLAN': ExplainResult[] }>( |