P PasteCode
Indicación

Prompt para añadir búsqueda de texto completo en PostgreSQL

Prompt de IA para copiar y pegar que añade búsqueda de texto completo nativa de PostgreSQL con tsvector, índice GIN y resultados clasificados a una aplicación Next.js existente.

CursorClaude CodeCodexWindsurf Next.jsPostgreSQLTypeScript
.md .json Dificultad: Medio Actualizado 8 jun 2026

Usa este prompt para añadir búsqueda de texto completo real de PostgreSQL a una aplicación existente — usando tsvector, un índice GIN y ts_rank — sin que el agente recurra a Elasticsearch, Algolia o una API de búsqueda de terceros.

Prompt Principal

Main Prompt
You are working in a Next.js App Router project with TypeScript and PostgreSQL (using the
`postgres` npm package, not Prisma or Drizzle).
Task: add full-text search over the `posts` table (columns: id, title, body, created_at).
Database changes:
1. Write a migration file `migrations/0010_add_fts.sql` that:
- Adds a generated column: `search_vector tsvector GENERATED ALWAYS AS
(to_tsvector('english', coalesce(title,'') || ' ' || coalesce(body,''))) STORED;`
- Creates a GIN index: `CREATE INDEX posts_search_idx ON posts USING GIN (search_vector);`
2. Do NOT use `pg_trgm` or LIKE queries — use `@@` with `to_tsquery` or `websearch_to_tsquery`.
Application changes:
- Create `src/lib/search.ts` with a `searchPosts(query: string, limit = 20)` function that:
- Uses `websearch_to_tsquery('english', $1)` to parse the query safely.
- Returns rows ordered by `ts_rank(search_vector, query_vector) DESC`.
- Returns `{ id, title, body_excerpt, rank }` — body_excerpt via `ts_headline`.
- Uses parameterized queries only — no string interpolation.
- Create a Server Action `src/lib/actions/search.ts` that calls `searchPosts` and returns results.
- Create `src/components/SearchBox.tsx` (Client Component) with a debounced input (300 ms) that
calls the Server Action via `useTransition` and renders results.
Do not install pg_search, Meilisearch, or any search service. Stop and list files before coding.

Notas de Implementación

  • websearch_to_tsquery es más seguro que to_tsquery para entrada de usuario porque tolera consultas mal formadas (operadores faltantes, caracteres especiales) sin lanzar un error de PostgreSQL.
  • La columna tsvector generada se actualiza automáticamente en INSERT/UPDATE — no se necesitan disparadores.
  • ts_headline requiere el texto original de la columna y el vector de consulta; pasa ambos desde el SELECT.
  • El índice GIN hace que la búsqueda sea rápida en tablas grandes; sin él, las consultas harán un escaneo secuencial.

Cambios de Archivos Esperados

migrations/0010_add_fts.sql (new)
src/lib/search.ts (new)
src/lib/actions/search.ts (new — Server Action)
src/components/SearchBox.tsx (new — Client Component)

Criterios de Aceptación

  • psql -f migrations/0010_add_fts.sql se ejecuta sin errores en el esquema existente.
  • Buscar una palabra que aparece solo en title devuelve la publicación correcta.
  • Buscar una frase con un error tipográfico (por ejemplo, “postgress”) no devuelve resultados sin fallar.
  • Los resultados se ordenan con las publicaciones de mayor relevancia primero.

Comandos de Prueba

Terminal window
psql "$DATABASE_URL" -f migrations/0010_add_fts.sql
bun run typecheck
bun run dev
# type a search term in SearchBox and verify ranked results appear
psql "$DATABASE_URL" -c "EXPLAIN ANALYZE SELECT * FROM posts WHERE search_vector @@ websearch_to_tsquery('english','test');"
# confirm "Index Scan using posts_search_idx" appears in output

Errores Comunes de IA

  • Usar LIKE '%query%' en lugar del operador de texto completo @@.
  • Usar to_tsquery('english', $1) con entrada de usuario sin procesar — se rompe en consultas como "foo bar".
  • Olvidar el índice GIN, dejando la búsqueda como un escaneo secuencial.
  • Llamar a searchPosts en un Componente Cliente en lugar de envolverlo en una Acción del Servidor.

Prompt de Corrección

Fix Prompt
The search is using LIKE or crashing on special characters. Fix in order:
1. Replace any LIKE clause with `search_vector @@ websearch_to_tsquery('english', $1)`.
2. If `to_tsquery` is used directly with user input, replace it with `websearch_to_tsquery`.
3. Confirm the GIN index exists: `CREATE INDEX IF NOT EXISTS posts_search_idx ON posts USING GIN (search_vector);`
Show only the corrected diff. Do not modify unrelated files.