examples/extend-full-text-search/README.md
This project demonstrates how to use Prisma's Full-Text Search on PostgreSQL with Keystone, using extendPrismaSchema to enable the fullTextSearchPostgres preview feature and a custom GraphQL query to expose it.
Note: This example requires a running PostgreSQL database. Full-text search is not available on SQLite.
To run this project, clone the Keystone repository locally then run pnpm install at the root of the repository.
Set your database URL:
export DATABASE_URL="postgresql://localhost/keystone-example"
Then navigate to this directory and run:
pnpm dev
This will start the Admin UI at localhost:3000. You can use the Admin UI to create items in your database.
You can also access a GraphQL Playground at localhost:3000/api/graphql, which allows you to directly run GraphQL queries and mutations.
extendPrismaSchemaPrisma's fullTextSearchPostgres is a preview feature that must be explicitly enabled in the Prisma generator block. Since Keystone manages the schema.prisma file automatically, you can inject this using extendPrismaSchema in your Keystone config:
db: {
provider: 'postgresql',
extendPrismaSchema: schema => {
return schema.replace(
/(generator [^}]+)}/g,
['$1', ' previewFeatures = ["fullTextSearchPostgres"]', '}'].join('\n')
)
},
}
This produces a generator block like:
generator client {
provider = "prisma-client"
output = "./generated/prisma"
previewFeatures = ["fullTextSearchPostgres"]
}
searchPosts QueryPrisma's search operator is a low-level Prisma feature not yet surfaced through Keystone's context.db query layer. To use it, the example reaches for the raw Prisma client via context.prisma, then converts the results back to Keystone-typed objects using context.db:
// 1. Use raw Prisma client to perform the full-text search
const matches = await context.prisma.post.findMany({
where: {
OR: [{ title: { search: query } }, { content: { search: query } }],
},
select: { id: true },
})
// 2. Fetch proper Keystone Post objects using the matched IDs
const ids = matches.map(p => p.id)
return context.db.Post.findMany({ where: { id: { in: ids } } })
The query argument accepts PostgreSQL's tsquery syntax:
| Operator | Meaning | Example |
|---|---|---|
& | AND | "cat & dog" — must contain both |
| | OR | "cat | dog" — must contain either |
! | NOT | "!cat" — must not contain |
<-> | Phrase/proximity | "fox <-> dog" — "dog" follows immediately after "fox" |
After creating some posts in the Admin UI, open localhost:3000/api/graphql and run:
query {
searchPosts(query: "keystone & graphql") {
id
title
content
author {
name
}
}
}