Files
supabase/apps/studio/data/privileges/keys.ts
Charis ec64135f9d perf(pg-meta): scope column privileges query to a single table (#48553)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Performance improvement

## What is the current behavior?

The column privileges page in Studio only ever renders one table, but
the underlying query still `aclexplode`s every column in the whole
schema and filters the result client-side.

## What is the new behavior?

Adds a scoped SQL path that prunes `pg_class`/`pg_namespace` to the
requested schema+table before exploding ACLs, gated behind the
`pgMetaScopedIntrospection` flag, with a plan-guard test asserting
`pg_class`/`pg_attribute` stay index-driven. Studio's query hook and
cache keys now thread the selected table through so column-privilege
invalidation and cold-load races are scoped correctly, and the page
fetches per-table instead of per-schema.

## Additional context

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Improvements**
* Column privileges are now scoped to the selected schema and table for
more accurate results.
* Changing schemas automatically updates the table selection and
refreshes the displayed privileges.
* Privilege updates now refresh only the relevant schema, table, and
column data.
* Loading states are handled more accurately when no table is selected.

* **Bug Fixes**
* Improved consistency between scoped and unscoped column privilege
results, including table-, column-, and grant-option privileges.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-31 15:26:37 -04:00

58 lines
2.0 KiB
TypeScript

export const privilegeKeys = {
tablePrivilegesList: (projectRef: string | undefined, includedSchemas?: string[]) =>
['projects', projectRef, 'database', 'table-privileges', includedSchemas].filter(Boolean),
columnPrivilegesList: (
projectRef: string | undefined,
schema?: string | undefined,
table?: string | undefined
) => {
const base = ['projects', projectRef, 'database', 'column-privileges'].filter(Boolean)
if (table === undefined) return schema === undefined ? base : [...base, schema]
return [...base, schema ?? null, table]
},
exposedTablesInfinite: (projectRef: string | undefined, search?: string) =>
[
'projects',
projectRef,
'privileges',
'exposed-tables-infinite',
...(search ? ([{ search }] as const) : []),
] as const,
exposedTablesAll: (projectRef: string | undefined) =>
['projects', projectRef, 'privileges', 'exposed-tables-all'] as const,
exposedFunctionsAll: (projectRef: string | undefined) =>
['projects', projectRef, 'privileges', 'exposed-functions-all'] as const,
exposedTableCounts: (projectRef: string | undefined, selectedSchemas?: string[]) =>
[
'projects',
projectRef,
'privileges',
'exposed-table-counts',
...(selectedSchemas ? ([selectedSchemas] as const) : []),
] as const,
exposedFunctionsInfinite: (projectRef: string | undefined, search?: string) =>
[
'projects',
projectRef,
'privileges',
'exposed-functions-infinite',
...(search ? ([{ search }] as const) : []),
] as const,
exposedFunctionCounts: (projectRef: string | undefined, selectedSchemas?: string[]) =>
[
'projects',
projectRef,
'privileges',
'exposed-function-counts',
...(selectedSchemas ? ([selectedSchemas] as const) : []),
] as const,
defaultPrivileges: (projectRef: string | undefined, schema?: string) =>
[
'projects',
projectRef,
'privileges',
'default-privileges',
...(schema ? [schema] : []),
] as const,
}