useSetIntrospection.ts67 lines · main
| 1 | import { ident, literal, safeSql } from '@supabase/pg-meta' |
| 2 | import { useQueryClient } from '@tanstack/react-query' |
| 3 | import { toast } from 'sonner' |
| 4 | |
| 5 | import { buildSchemaCommentWith, parseSchemaComment } from './pgGraphqlSchemaComment' |
| 6 | import { pgGraphqlKeys } from '@/data/pg-graphql/keys' |
| 7 | import { useExecuteSqlMutation } from '@/data/sql/execute-sql-mutation' |
| 8 | import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' |
| 9 | |
| 10 | interface UseSetIntrospectionParams { |
| 11 | schema: string |
| 12 | currentSchemaComment: string | null | undefined |
| 13 | /** Target state — true enables introspection, false disables it. */ |
| 14 | enabled: boolean |
| 15 | /** Fires synchronously when the mutation succeeds, before query invalidation — use to close the confirmation modal. */ |
| 16 | onMutationSuccess: () => void |
| 17 | /** Fires after dependent queries are invalidated — use to trigger remounts that depend on fresh data. */ |
| 18 | onInvalidated: () => void |
| 19 | } |
| 20 | |
| 21 | export const useSetIntrospection = ({ |
| 22 | schema, |
| 23 | currentSchemaComment, |
| 24 | enabled, |
| 25 | onMutationSuccess, |
| 26 | onInvalidated, |
| 27 | }: UseSetIntrospectionParams) => { |
| 28 | const { data: project } = useSelectedProjectQuery() |
| 29 | const queryClient = useQueryClient() |
| 30 | |
| 31 | const parsed = parseSchemaComment(currentSchemaComment) |
| 32 | const nextComment = buildSchemaCommentWith(currentSchemaComment, { introspection: enabled }) |
| 33 | const sql = safeSql`comment on schema ${ident(schema)} is ${literal(nextComment)};` |
| 34 | |
| 35 | // If the existing directive was unparseable we'd be silently discarding the |
| 36 | // user's prior options. Surface that so the UI can warn before confirming. |
| 37 | const existingDirectiveIsMalformed = parsed.hasDirective && parsed.isMalformed |
| 38 | const otherExistingKeys = Object.keys(parsed.options).filter((k) => k !== 'introspection') |
| 39 | |
| 40 | const pastVerb = enabled ? 'enabled' : 'disabled' |
| 41 | const presentVerb = enabled ? 'enable' : 'disable' |
| 42 | |
| 43 | const { mutate, isPending } = useExecuteSqlMutation({ |
| 44 | onSuccess: async (_data, variables) => { |
| 45 | toast.success(`Introspection ${pastVerb} on schema "${schema}".`) |
| 46 | onMutationSuccess() |
| 47 | await queryClient.invalidateQueries({ |
| 48 | queryKey: pgGraphqlKeys.schemaComment(variables.projectRef, schema), |
| 49 | }) |
| 50 | onInvalidated() |
| 51 | }, |
| 52 | onError: (error) => { |
| 53 | toast.error(`Failed to ${presentVerb} introspection: ${error.message}`) |
| 54 | }, |
| 55 | }) |
| 56 | |
| 57 | const apply = () => { |
| 58 | if (!project?.ref) return |
| 59 | mutate({ |
| 60 | projectRef: project.ref, |
| 61 | connectionString: project.connectionString, |
| 62 | sql, |
| 63 | }) |
| 64 | } |
| 65 | |
| 66 | return { apply, isPending, sql, existingDirectiveIsMalformed, otherExistingKeys } |
| 67 | } |