usePgGraphqlIntrospectionStatus.ts 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. import { useMemo } from 'react'
  2. import { PG_GRAPHQL_EXTENSION_NAME } from './constants'
  3. import {
  4. isIntrospectionEnabled,
  5. isPgGraphqlIntrospectionOptIn,
  6. parseSchemaComment,
  7. } from './pgGraphqlSchemaComment'
  8. import { useDatabaseExtensionsQuery } from '@/data/database-extensions/database-extensions-query'
  9. import { useSchemaCommentQuery } from '@/data/pg-graphql/schema-comment-query'
  10. type UsePgGraphqlIntrospectionStatusArgs = {
  11. projectRef: string | undefined
  12. connectionString: string | null | undefined
  13. schema: string
  14. enabled?: boolean
  15. }
  16. /**
  17. * Which introspection notice (if any) should be shown for a pg_graphql >= 1.6 project:
  18. * - `opt-in`: introspection is currently off — prompt to enable.
  19. * - `opt-out`: introspection is currently on — surface a control to disable.
  20. * - `null`: nothing to show (version doesn't require opt-in, or still loading).
  21. */
  22. export type IntrospectionNotice = 'opt-in' | 'opt-out' | null
  23. export type PgGraphqlIntrospectionStatus = {
  24. /** True while either underlying query is still loading. */
  25. isLoading: boolean
  26. notice: IntrospectionNotice
  27. /** The raw schema comment string, or null when there is no comment yet. */
  28. schemaComment: string | null | undefined
  29. }
  30. export const usePgGraphqlIntrospectionStatus = ({
  31. projectRef,
  32. connectionString,
  33. schema,
  34. enabled = true,
  35. }: UsePgGraphqlIntrospectionStatusArgs): PgGraphqlIntrospectionStatus => {
  36. const { data: pgGraphqlVersion, isLoading: isVersionLoading } = useDatabaseExtensionsQuery<
  37. string | null
  38. >(
  39. { projectRef, connectionString },
  40. {
  41. enabled,
  42. select: (extensions) =>
  43. extensions.find((ext) => ext.name === PG_GRAPHQL_EXTENSION_NAME)?.installed_version ?? null,
  44. }
  45. )
  46. // Only fetch the schema comment when the installed version actually requires
  47. // the opt-in. Older versions enable introspection by default, so the comment
  48. // is irrelevant for the notice.
  49. const versionRequiresOptIn = isPgGraphqlIntrospectionOptIn(pgGraphqlVersion)
  50. const {
  51. data: schemaComment,
  52. isLoading: isCommentLoading,
  53. isError: isCommentError,
  54. } = useSchemaCommentQuery(
  55. { projectRef, connectionString, schema },
  56. { enabled: enabled && versionRequiresOptIn }
  57. )
  58. const notice = useMemo<IntrospectionNotice>(() => {
  59. if (!versionRequiresOptIn) return null
  60. if (isCommentLoading || isCommentError) return null
  61. const parsed = parseSchemaComment(schemaComment)
  62. return isIntrospectionEnabled(parsed.options) ? 'opt-out' : 'opt-in'
  63. }, [versionRequiresOptIn, schemaComment, isCommentLoading, isCommentError])
  64. return {
  65. isLoading: isVersionLoading || (versionRequiresOptIn && isCommentLoading),
  66. notice,
  67. schemaComment,
  68. }
  69. }