pg-smart-search
Examples

Examples

Real-world implementation patterns and code snippets for integrating pg-smart-search into your application.

Examples

Practical implementations of pg-smart-search in common frameworks and use cases.

Next.js API Route

Create a search API endpoint in your Next.js App Router application.

import { NextRequest, NextResponse } from 'next/server';
import { TrigramSearchEngine, MemoryCacheProvider } from 'pg-smart-search';
import { dbAdapter } from '@/lib/db';

const engine = new TrigramSearchEngine(dbAdapter, {
  tableName: 'posts',
  searchColumns: ['title', 'content'],
  cacheProvider: new MemoryCacheProvider(),
});

export async function GET(request: NextRequest) {
  const searchParams = request.nextUrl.searchParams;
  const query = searchParams.get('q');
  const cursor = searchParams.get('cursor');

  if (!query) {
    return NextResponse.json({ error: 'Query parameter "q" is required' }, { status: 400 });
  }

  // cursor is only valid against the id-ordered STANDARD/LITE path -- see
  // /docs/guides/pagination for why it can't be combined with fuzzy fallback.
  const results = await engine.search({
    query,
    cursor: cursor || undefined,
    limit: 20,
  });

  return NextResponse.json(results);
}
import type { NextApiRequest, NextApiResponse } from 'next';
import { TrigramSearchEngine, MemoryCacheProvider } from 'pg-smart-search';
import { dbAdapter } from '@/lib/db';

const engine = new TrigramSearchEngine(dbAdapter, {
  tableName: 'posts',
  searchColumns: ['title', 'content'],
  cacheProvider: new MemoryCacheProvider(),
});

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method !== 'GET') return res.status(405).end();

  const { q, cursor } = req.query;

  if (!q || typeof q !== 'string') {
    return res.status(400).json({ error: 'Query parameter "q" is required' });
  }

  const results = await engine.search({
    query: q,
    cursor: (cursor as string) || undefined,
    limit: 20,
  });

  return res.status(200).json(results);
}

E-Commerce Product Search with Filters

Implement a product search that supports filtering by category and price range.

import { TrigramSearchEngine } from "pg-smart-search";

const engine = new TrigramSearchEngine(adapter, {
  tableName: "products",
  searchColumns: ["name", "description"],
  ftsColumn: "search_vector",
});

const results = await engine.search({
  query: "wireless headphones",
  filters: {
    category: "electronics", // plain scalar -> "category" = $n
    price: { between: [50, 200] }, // typed operator -> "price" BETWEEN $n AND $n+1
  },
  limit: 20,
});

Pagination with Infinite Scroll

Implement cursor-based pagination for a frontend infinite scroll component. There's no nextCursor field on the result -- you build the next cursor yourself from the last row's own id column. Cursor pagination only works against the id-ordered STANDARD/LITE tier; it throws UnsupportedCursorError on relevance-sorted searches (ADVANCED/VECTOR/fuzzy fallback).

// Initial fetch (page-based, since there's no cursor yet)
const firstPage = await engine.search({
  query: "laptop",
  limit: 15,
});

// Subsequent fetch: cursor is the id of the last row you saw
const lastRow = firstPage.data[firstPage.data.length - 1] as { id: number };
const nextPage = await engine.search({
  query: "laptop",
  limit: 15,
  cursor: lastRow.id,
});

if (!nextPage.pagination.hasNext) {
  console.log("Reached the end of results");
}