Files
supabase/apps/docs/resources/globalSearch/globalSearchResolver.ts
T
Charis df4b1867b8 feat (content api): add global search query (#35290)
Add a top-level field to search docs globally. Right now this only
returns Markdown guides (not references, GitHub discussions, or partner
pages.

The full GraphQL schema at this point:

```
schema {
  query: RootQueryType
}

type RootQueryType {
  """Get the GraphQL schema for this endpoint"""
  schema: String!

  """Search the Supabase docs for content matching a query string"""
  searchDocs(query: String!, limit: Int): SearchResultCollection
}

"""A collection of search results containing content from Supabase docs"""
type SearchResultCollection {
  """A list of edges containing nodes in this collection"""
  edges: [SearchResultEdge!]!

  """The nodes in this collection, directly accessible"""
  nodes: [SearchResult!]!

  """The total count of items available in this collection"""
  totalCount: Int!
}

"""An edge in a collection of SearchResults"""
type SearchResultEdge {
  """The SearchResult at the end of the edge"""
  node: SearchResult!
}

"""Document that matches a search query"""
interface SearchResult {
  """The title of the matching result"""
  title: String

  """The URL of the matching result"""
  href: String

  """The full content of the matching result"""
  content: String
}
```

Towards DOCS-214
2025-05-05 14:32:10 -04:00

71 lines
2.1 KiB
TypeScript

import {
GraphQLError,
GraphQLInt,
GraphQLNonNull,
GraphQLString,
type GraphQLResolveInfo,
} from 'graphql'
import {
type RootQueryTypeSearchDocsArgs,
type SearchResultCollection,
} from '~/__generated__/graphql'
import { convertUnknownToApiError, type ApiErrorGeneric } from '~/app/api/utils'
import { Result } from '~/features/helpers.fn'
import { createCollectionType, GraphQLCollectionBuilder } from '../utils/connections'
import { graphQLFields } from '../utils/fields'
import { SearchResultModel } from './globalSearchModel'
import { GRAPHQL_FIELD_SEARCH_GLOBAL, GraphQLInterfaceTypeSearchResult } from './globalSearchSchema'
async function resolveSearch(
parent: unknown,
args: RootQueryTypeSearchDocsArgs,
context: unknown,
info: GraphQLResolveInfo
): Promise<SearchResultCollection | GraphQLError> {
return (
await Result.tryCatchFlat(
resolveSearchImpl,
convertUnknownToApiError,
parent,
args,
context,
info
)
).match(
(data) => GraphQLCollectionBuilder.create({ items: data }),
(error) => {
console.error(`Error resolving ${GRAPHQL_FIELD_SEARCH_GLOBAL}:`, error)
return new GraphQLError(error.isPrivate() ? 'Internal Server Error' : error.message)
}
)
}
async function resolveSearchImpl(
_parent: unknown,
args: RootQueryTypeSearchDocsArgs,
_context: unknown,
info: GraphQLResolveInfo
): Promise<Result<Array<SearchResultModel>, ApiErrorGeneric>> {
const requestedFields = Object.keys(graphQLFields(info).nodes)
return await SearchResultModel.search(args, requestedFields)
}
export const searchRoot = {
[GRAPHQL_FIELD_SEARCH_GLOBAL]: {
description: 'Search the Supabase docs for content matching a query string',
args: {
query: {
type: new GraphQLNonNull(GraphQLString),
},
limit: {
type: GraphQLInt,
},
},
type: createCollectionType(GraphQLInterfaceTypeSearchResult, {
skipPageInfo: true,
description: 'A collection of search results containing content from Supabase docs',
}),
resolve: resolveSearch,
},
}