Files
supabase/apps/studio/data/table-editor/table-editor-query.ts
T
Joshen Lim eb20a4674d getTableDefinitionSql to escape SQL identifiers (#51258)
## Context

Similar to domain to https://github.com/supabase/supabase/pull/51256 -
`getTableDefinitionSql` doesn't escape SQL identifiers, which generates
invalid SQL on the dashboard's table editor for the "Copy table schema"
CTA, or the table definition tab.

Also fixes the "Copy table schema" CTA which was missing the `scoped`
parameter when calling `getTableDefinition`

Changes here addresses this issue, can test with a table named like
`test"table`
2026-10-06 21:34:36 +08:00

85 lines
2.5 KiB
TypeScript

import { getTableEditorSql } from '@supabase/pg-meta'
import { QueryClient, queryOptions, useQuery } from '@tanstack/react-query'
import { useFlag } from 'common'
import { tableEditorKeys } from './keys'
import { Entity } from './table-editor-types'
import { executeSql } from '@/data/sql/execute-sql-mutation'
import { ResponseError, UseCustomQueryOptions } from '@/types'
export const PG_META_SCOPED_INTROSPECTION_FLAG = 'pgMetaScopedIntrospection'
type TableEditorArgs = {
id?: number
scoped?: boolean
}
export type TableEditorVariables = TableEditorArgs & {
projectRef?: string
connectionString?: string | null
}
export async function getTableEditor(
{ projectRef, connectionString, id, scoped = false }: TableEditorVariables,
signal?: AbortSignal
) {
if (!id) {
throw new Error('id is required')
}
const sql = getTableEditorSql({ id, scoped })
const { result } = await executeSql(
{
projectRef,
connectionString,
sql,
queryKey: ['table-editor', id],
},
signal
)
return (result[0]?.entity ?? null) as Entity | undefined
}
export type TableEditorData = Awaited<ReturnType<typeof getTableEditor>>
export type TableEditorError = ResponseError
export const useTableEditorQuery = <TData = TableEditorData>(
{ projectRef, connectionString, id }: TableEditorVariables,
{
enabled = true,
...options
}: UseCustomQueryOptions<TableEditorData, TableEditorError, TData> = {}
) => {
const scoped = useFlag(PG_META_SCOPED_INTROSPECTION_FLAG)
return useQuery<TableEditorData, TableEditorError, TData>({
...tableEditorQueryOptions({ projectRef, connectionString, id, scoped }),
enabled:
enabled && typeof projectRef !== 'undefined' && typeof id !== 'undefined' && !isNaN(id),
refetchOnWindowFocus: false,
refetchOnMount: false,
staleTime: 5 * 60 * 1000,
...options,
})
}
export function prefetchTableEditor(
client: QueryClient,
{ projectRef, connectionString, id, scoped }: TableEditorVariables
) {
return client.fetchQuery(tableEditorQueryOptions({ projectRef, connectionString, id, scoped }))
}
export const tableEditorQueryOptions = <TData = TableEditorData>({
projectRef,
connectionString,
id,
scoped,
}: TableEditorVariables) => {
return queryOptions<TableEditorData, TableEditorError, TData>({
queryKey: [...tableEditorKeys.tableEditor(projectRef, id), { scoped: !!scoped }],
queryFn: ({ signal }) => getTableEditor({ projectRef, connectionString, id, scoped }, signal),
})
}