spb/cancerindex
Public
TypeScript 97.2%
SQL 1.5%
CSS 0.6%
JavaScript 0.5%
1import type { FastifyPluginAsyncZod } from 'fastify-type-provider-zod';2import { z } from 'zod';3import { searchAll, type SearchType } from '../lib/search.js';4import { ok, respond } from '../lib/respond.js';56const Result = z.object({ type: z.enum(['cancer', 'gene', 'variant', 'drug', 'trial', 'publication']), id: z.string(), slug: z.string(), name: z.string(), subtitle: z.string().nullable(), score: z.number(), match: z.enum(['exact', 'alias', 'prefix', 'fuzzy']) });78export const searchRoutes: FastifyPluginAsyncZod = async (app) => {9 app.get('/search', { schema: { tags: ['search'], summary: 'Cross-entity search (exact > alias > prefix > fuzzy; deterministic order; max 20)', querystring: z.object({ q: z.string().trim().min(1).max(200), types: z.string().optional().describe('Comma-separated subset of cancer,gene,variant,drug,trial,publication'), limit: z.coerce.number().int().min(1).max(20).default(20) }), response: ok(z.array(Result)) } }, async (req) => {10 const types = req.query.types11 ?.split(',')12 .map((t) => t.trim())13 .filter((t): t is SearchType => ['cancer', 'gene', 'variant', 'drug', 'trial', 'publication'].includes(t));14 const results = await searchAll(app.db, req.query.q, types, req.query.limit);15 return respond(app, results, []);16 });17};18