export const prerender = false; import type { APIRoute } from "astro"; import { and, eq, gt, sql } from "drizzle-orm"; import { createDb } from "@/db"; import { events, profiles } from "@/db/schema"; export const GET: APIRoute = async ({ url, locals }) => { const q = url.searchParams.get("q")?.trim(); if (!q || q.length < 2 || q.length > 200) { return Response.json( { events: [], profiles: [] }, { headers: { "Cache-Control": "public, s-maxage=30" } }, ); } const runtime = locals.runtime as { env: { DATABASE_URL: string } }; const db = createDb(runtime.env.DATABASE_URL); const tsquery = sql`websearch_to_tsquery('english', ${q})`; const [matchedEvents, matchedProfiles] = await Promise.all([ db .select({ slug: events.slug, title: events.title, rank: sql`ts_rank(search_vector, ${tsquery})`, }) .from(events) .where(and(sql`search_vector @@ ${tsquery}`, eq(events.active, true))) .orderBy(sql`ts_rank(search_vector, ${tsquery}) desc`) .limit(5), db .select({ username: profiles.username, similarity: sql`similarity(${profiles.username}, ${q})`, }) .from(profiles) .where(and(gt(sql`similarity(${profiles.username}, ${q})`, 0.1), eq(profiles.active, true))) .orderBy(sql`similarity(${profiles.username}, ${q}) desc`) .limit(5), ]); if (matchedEvents.length === 0) { const fuzzyEvents = await db .select({ slug: events.slug, title: events.title, similarity: sql`similarity(${events.title}, ${q})`, }) .from(events) .where(and(gt(sql`similarity(${events.title}, ${q})`, 0.1), eq(events.active, true))) .orderBy(sql`similarity(${events.title}, ${q}) desc`) .limit(5); return Response.json( { events: fuzzyEvents, profiles: matchedProfiles }, { headers: { "Cache-Control": "public, s-maxage=30" } }, ); } return Response.json( { events: matchedEvents, profiles: matchedProfiles }, { headers: { "Cache-Control": "public, s-maxage=30" } }, ); };