Files
supabase/apps/studio/hooks/useProtectedSchemas.ts
Joshen Lim cab0585533 Fe 1799/consolidate to useselectedprojectquery and (#37684)
* Replace all usage of useProjectContext with useSelectedProjectQuery

* Replace all usage of useSelectedProject with useSelectedProjectQuery

* Replace all usage of useProjectByRef with useProjectByRefQuery

* Replace all usage of useSelectedOrganization with useSelectedOrganizationQuery

* Deprecate useSelectedProject, useSelectedOrganization, and useProjectByRef hooks

* Deprecate ProjecContext
2025-08-06 10:53:10 +07:00

113 lines
3.3 KiB
TypeScript

import { uniq } from 'lodash'
import { useMemo } from 'react'
import { WRAPPER_HANDLERS } from 'components/interfaces/Integrations/Wrappers/Wrappers.constants'
import {
convertKVStringArrayToJson,
wrapperMetaComparator,
} from 'components/interfaces/Integrations/Wrappers/Wrappers.utils'
import { QUEUES_SCHEMA } from 'data/database-queues/database-queues-toggle-postgrest-mutation'
import { useFDWsQuery } from 'data/fdw/fdws-query'
import { useSelectedProjectQuery } from './misc/useSelectedProject'
/**
* A list of system schemas that users should not interact with
*/
export const INTERNAL_SCHEMAS = [
'auth',
'cron',
'extensions',
'information_schema',
'net',
'pgsodium',
'pgsodium_masks',
'pgbouncer',
'pgtle',
'realtime',
'storage',
'supabase_functions',
'supabase_migrations',
'vault',
'graphql',
'graphql_public',
QUEUES_SCHEMA,
]
/**
* Get the list of schemas used by IcebergFDWs
*/
const useIcebergFdwSchemasQuery = () => {
const { data: project } = useSelectedProjectQuery()
const result = useFDWsQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
})
const schemas = useMemo(() => {
const icebergFDWs = result.data?.filter((wrapper) =>
wrapperMetaComparator(
{ handlerName: WRAPPER_HANDLERS.ICEBERG, server: { options: [] } },
wrapper
)
)
const fdwSchemas = icebergFDWs
?.map((fdw) => convertKVStringArrayToJson(fdw.server_options))
.map((options) => options['supabase_target_schema'])
.flatMap((s) => s?.split(','))
.filter(Boolean)
return uniq(fdwSchemas)
}, [result.data])
return { ...result, data: schemas }
}
/**
* Returns a list of schemas that are protected by Supabase (internal schemas or schemas used by Iceberg FDWs).
*/
export const useProtectedSchemas = ({
excludeSchemas = [],
}: { excludeSchemas?: string[] } = {}) => {
// Stabilize the excludeSchemas array to prevent unnecessary re-computations
// eslint-disable-next-line react-hooks/exhaustive-deps
const stableExcludeSchemas = useMemo(() => excludeSchemas, [JSON.stringify(excludeSchemas)])
const result = useIcebergFdwSchemasQuery()
const schemas = useMemo<{ name: string; type: 'fdw' | 'internal' }[]>(() => {
const internalSchemas = INTERNAL_SCHEMAS.map((s) => ({ name: s, type: 'internal' as const }))
const icebergFdwSchemas = result.data?.map((s) => ({ name: s, type: 'fdw' as const }))
const schemas = uniq([...internalSchemas, ...icebergFdwSchemas])
return schemas.filter((schema) => !stableExcludeSchemas.includes(schema.name))
}, [result.data, stableExcludeSchemas])
return { ...result, data: schemas }
}
/**
* Returns whether a given schema is protected by Supabase (internal schema or schema used by Iceberg FDWs).
*/
export const useIsProtectedSchema = ({
schema,
excludedSchemas = [],
}: {
schema: string
excludedSchemas?: string[]
}):
| { isSchemaLocked: false; reason: undefined }
| { isSchemaLocked: true; reason: 'fdw' | 'internal' } => {
const { data: schemas } = useProtectedSchemas({ excludeSchemas: excludedSchemas })
const foundSchema = schemas.find((s) => s.name === schema)
if (foundSchema) {
return {
isSchemaLocked: true,
reason: foundSchema.type,
}
}
return { isSchemaLocked: false, reason: undefined }
}