UNPKG

graphile-search-plugin

Version:

Generate search conditions for your tsvector columns (PostGraphile v5)

76 lines (75 loc) 3.46 kB
/** * PostGraphile v5 Search Plugin * * Generates search condition fields for tsvector columns. When a search term * is provided via the condition input, this plugin applies a * `column @@ websearch_to_tsquery('english', $value)` WHERE clause. * Results are ordered by `ts_rank` only when explicitly requested via * the `FULL_TEXT_RANK_ASC/DESC` orderBy enum values (not automatically), * ensuring cursor pagination digests remain stable across pages. * * Additionally provides: * - `matches` filter operator for postgraphile-plugin-connection-filter * - `fullTextRank` computed fields on output types (null when no search active) * - `FULL_TEXT_RANK_ASC/DESC` orderBy enum values * * Uses the graphile-build hooks API to extend condition input types with * search fields for each tsvector column found on a table's codec. * * ARCHITECTURE NOTE: * Uses the Grafast meta system (setMeta/getMeta) to pass data between * the condition apply phase, the orderBy enum apply, and the output field * plan, following the pattern from Benjie's postgraphile-plugin-fulltext-filter. * * 1. Condition apply (runs first): adds ts_rank to the query builder's * SELECT list via selectAndReturnIndex, stores { selectIndex, scoreFragment } * in meta via qb.setMeta(key, { selectIndex, scoreFragment }). * 2. OrderBy enum apply (runs second): reads the scoreFragment from meta * and calls qb.orderBy({ fragment, codec, direction }) directly. * 3. Output field plan (planning phase): calls $select.getMeta(key) which * returns a Grafast Step that resolves at execution time. * 4. lambda([$details, $row]) reads the rank from row[details.selectIndex]. */ import 'graphile-build'; import 'graphile-build-pg'; import type { PgCodecWithAttributes, PgResource } from '@dataplan/pg'; import type { GraphileConfig } from 'graphile-config'; import type { PgSearchPluginOptions } from './types'; declare global { namespace GraphileBuild { interface Inflection { /** Name for the FullText scalar type */ fullTextScalarTypeName(this: Inflection): string; /** Name for the rank field (e.g. "bodyRank") */ pgTsvRank(this: Inflection, fieldName: string): string; /** Name for orderBy enum value for column rank */ pgTsvOrderByColumnRankEnum(this: Inflection, codec: PgCodecWithAttributes, attributeName: string, ascending: boolean): string; /** Name for orderBy enum value for computed column rank */ pgTsvOrderByComputedColumnRankEnum(this: Inflection, codec: PgCodecWithAttributes, resource: PgResource, ascending: boolean): string; } interface ScopeObjectFieldsField { isPgTSVRankField?: boolean; } interface BehaviorStrings { 'attributeFtsRank:select': true; 'procFtsRank:select': true; 'attributeFtsRank:orderBy': true; 'procFtsRank:orderBy': true; } } namespace GraphileConfig { interface Plugins { PgSearchPlugin: true; } } } /** * Creates the search plugin with the given options. */ export declare function createPgSearchPlugin(options?: PgSearchPluginOptions): GraphileConfig.Plugin; /** * Creates a PgSearchPlugin with the given options. * This is the main entry point for using the plugin. */ export declare const PgSearchPlugin: typeof createPgSearchPlugin; export default PgSearchPlugin;