Skip to content

Commit f5c0a4c

Browse files
authored
fix: only use MAINTAIN for table privileges if PG17+ (supabase#30998)
* chore: use @supabase/pg-meta for table privileges queries * fix: only use MAINTAIN for table privileges if PG17+ * chore: run prettier
1 parent ec81fe6 commit f5c0a4c

File tree

9 files changed

+346
-142
lines changed

9 files changed

+346
-142
lines changed

apps/studio/components/interfaces/Database/Privileges/Privileges.utils.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
TablePrivilegesGrant,
1616
grantTablePrivileges,
1717
} from 'data/privileges/table-privileges-grant-mutation'
18-
import type { TablePrivilege } from 'data/privileges/table-privileges-query'
18+
import type { PgTablePrivileges } from 'data/privileges/table-privileges-query'
1919
import {
2020
TablePrivilegesRevoke,
2121
revokeTablePrivileges,
@@ -35,7 +35,7 @@ export interface PrivilegeOperation {
3535
privilege_type: string
3636
}
3737

38-
export function getDefaultTableCheckedStates(tablePrivilege: TablePrivilege) {
38+
export function getDefaultTableCheckedStates(tablePrivilege: PgTablePrivileges) {
3939
return Object.fromEntries(
4040
ALL_PRIVILEGE_TYPES.map((privilege) => [
4141
privilege,
@@ -286,16 +286,16 @@ export function useApplyPrivilegeOperations(callback?: () => void) {
286286
const grantTableOperations = tableOperations
287287
.filter((op) => op.type === 'grant')
288288
.map((op) => ({
289-
relation_id: Number(op.id),
289+
relationId: Number(op.id),
290290
grantee: op.grantee,
291-
privilege_type: op.privilege_type as TablePrivilegesGrant['privilege_type'],
291+
privilegeType: op.privilege_type as TablePrivilegesGrant['privilegeType'],
292292
}))
293293
const revokeTableOperations = tableOperations
294294
.filter((op) => op.type === 'revoke')
295295
.map((op) => ({
296-
relation_id: Number(op.id),
296+
relationId: Number(op.id),
297297
grantee: op.grantee,
298-
privilege_type: op.privilege_type as TablePrivilegesRevoke['privilege_type'],
298+
privilegeType: op.privilege_type as TablePrivilegesRevoke['privilegeType'],
299299
}))
300300

301301
const grantColumnOperations = columnOperations

apps/studio/components/interfaces/Integrations/Queues/SingleQueue/QueueSettings.tsx

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,8 @@ export const QueueSettings = ({}: QueueSettingsProps) => {
147147
connectionString: project.connectionString,
148148
revokes: revoke.map((x) => ({
149149
grantee: x.role,
150-
privilege_type: x.action.toUpperCase(),
151-
relation_id: queueTable.id,
150+
privilegeType: x.action.toUpperCase(),
151+
relationId: queueTable.id,
152152
})) as TablePrivilegesRevoke[],
153153
}),
154154
]
@@ -162,13 +162,13 @@ export const QueueSettings = ({}: QueueSettingsProps) => {
162162
revokes: [
163163
...rolesNoLongerHavingPerms.map((x) => ({
164164
grantee: x,
165-
privilege_type: 'INSERT' as 'INSERT',
166-
relation_id: archiveTable.id,
165+
privilegeType: 'INSERT' as const,
166+
relationId: archiveTable.id,
167167
})),
168168
...rolesNoLongerHavingPerms.map((x) => ({
169169
grantee: x,
170-
privilege_type: 'SELECT' as 'SELECT',
171-
relation_id: archiveTable.id,
170+
privilegeType: 'SELECT' as const,
171+
relationId: archiveTable.id,
172172
})),
173173
],
174174
}),
@@ -181,8 +181,8 @@ export const QueueSettings = ({}: QueueSettingsProps) => {
181181
connectionString: project.connectionString,
182182
grants: grant.map((x) => ({
183183
grantee: x.role,
184-
privilege_type: x.action.toUpperCase(),
185-
relation_id: queueTable.id,
184+
privilegeType: x.action.toUpperCase(),
185+
relationId: queueTable.id,
186186
})) as TablePrivilegesGrant[],
187187
}),
188188
// Just grant select + insert on archive table as long as we're granting any perms to the queue table for the role
@@ -192,13 +192,13 @@ export const QueueSettings = ({}: QueueSettingsProps) => {
192192
grants: [
193193
...rolesBeingGrantedPerms.map((x) => ({
194194
grantee: x,
195-
privilege_type: 'INSERT' as 'INSERT',
196-
relation_id: archiveTable.id,
195+
privilegeType: 'INSERT' as const,
196+
relationId: archiveTable.id,
197197
})),
198198
...rolesBeingGrantedPerms.map((x) => ({
199199
grantee: x,
200-
privilege_type: 'SELECT' as 'SELECT',
201-
relation_id: archiveTable.id,
200+
privilegeType: 'SELECT' as const,
201+
relationId: archiveTable.id,
202202
})),
203203
],
204204
}),

apps/studio/data/privileges/table-privileges-grant-mutation.ts

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
1+
import pgMeta from '@supabase/pg-meta'
12
import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query'
23
import { toast } from 'sonner'
34

4-
import type { components } from 'data/api'
5-
import { handleError, post } from 'data/fetchers'
5+
import { executeSql } from 'data/sql/execute-sql-query'
66
import type { ResponseError } from 'types'
7+
import { invalidateTablePrivilegesQuery } from './table-privileges-query'
78
import { privilegeKeys } from './keys'
89

9-
export type TablePrivilegesGrant = components['schemas']['GrantTablePrivilegesBody']
10+
export type TablePrivilegesGrant = Parameters<
11+
typeof pgMeta.tablePrivileges.grant
12+
>[0] extends (infer T)[]
13+
? T
14+
: never
1015

1116
export type TablePrivilegesGrantVariables = {
1217
projectRef: string
@@ -19,21 +24,14 @@ export async function grantTablePrivileges({
1924
connectionString,
2025
grants,
2126
}: TablePrivilegesGrantVariables) {
22-
const headers = new Headers()
23-
if (connectionString) headers.set('x-connection-encrypted', connectionString)
24-
25-
const { data, error } = await post('/platform/pg-meta/{ref}/table-privileges', {
26-
params: {
27-
path: { ref: projectRef },
28-
// this is needed to satisfy the typescript, but it doesn't pass the actual header
29-
header: { 'x-connection-encrypted': connectionString! },
30-
},
31-
body: grants,
32-
headers,
27+
const sql = pgMeta.tablePrivileges.grant(grants).sql
28+
const { result } = await executeSql({
29+
projectRef,
30+
connectionString,
31+
sql,
32+
queryKey: ['table-privileges', 'grant'],
3333
})
34-
35-
if (error) handleError(error)
36-
return data
34+
return result
3735
}
3836

3937
type TablePrivilegesGrantData = Awaited<ReturnType<typeof grantTablePrivileges>>
@@ -55,7 +53,7 @@ export const useTablePrivilegesGrantMutation = ({
5553
const { projectRef } = variables
5654

5755
await Promise.all([
58-
queryClient.invalidateQueries(privilegeKeys.tablePrivilegesList(projectRef)),
56+
invalidateTablePrivilegesQuery(queryClient, projectRef),
5957
queryClient.invalidateQueries(privilegeKeys.columnPrivilegesList(projectRef)),
6058
])
6159

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,39 @@
1-
import { UseQueryOptions, useQuery } from '@tanstack/react-query'
1+
import pgMeta from '@supabase/pg-meta'
2+
import { QueryClient, UseQueryOptions, useQuery } from '@tanstack/react-query'
3+
import { z } from 'zod'
24

3-
import type { components } from 'data/api'
4-
import { get, handleError } from 'data/fetchers'
5-
import type { ResponseError } from 'types'
5+
import { executeSql, ExecuteSqlError } from 'data/sql/execute-sql-query'
66
import { privilegeKeys } from './keys'
77

88
export type TablePrivilegesVariables = {
99
projectRef?: string
1010
connectionString?: string
1111
}
1212

13-
export type TablePrivilege = components['schemas']['PostgresTablePrivileges']
13+
export type PgTablePrivileges = z.infer<typeof pgMeta.tablePrivileges.zod>
1414

15-
export async function getTablePrivileges(
15+
const pgMetaTablePrivilegesList = pgMeta.tablePrivileges.list()
16+
17+
export type TablePrivilegesData = z.infer<typeof pgMetaTablePrivilegesList.zod>
18+
export type TablePrivilegesError = ExecuteSqlError
19+
20+
async function getTablePrivileges(
1621
{ projectRef, connectionString }: TablePrivilegesVariables,
1722
signal?: AbortSignal
1823
) {
19-
if (!projectRef) throw new Error('projectRef is required')
20-
21-
const headers = new Headers()
22-
if (connectionString) headers.set('x-connection-encrypted', connectionString)
23-
24-
const { data, error } = await get('/platform/pg-meta/{ref}/table-privileges', {
25-
params: {
26-
path: { ref: projectRef },
27-
// this is needed to satisfy the typescript, but it doesn't pass the actual header
28-
header: { 'x-connection-encrypted': connectionString! },
24+
const { result } = await executeSql(
25+
{
26+
projectRef,
27+
connectionString,
28+
sql: pgMetaTablePrivilegesList.sql,
29+
queryKey: ['table-privileges'],
2930
},
30-
signal,
31-
headers,
32-
})
31+
signal
32+
)
3333

34-
if (error) throw handleError(error)
35-
return data
34+
return result as TablePrivilegesData
3635
}
3736

38-
export type TablePrivilegesData = Awaited<ReturnType<typeof getTablePrivileges>>
39-
export type TablePrivilegesError = ResponseError
40-
4137
export const useTablePrivilegesQuery = <TData = TablePrivilegesData>(
4238
{ projectRef, connectionString }: TablePrivilegesVariables,
4339
{
@@ -53,3 +49,10 @@ export const useTablePrivilegesQuery = <TData = TablePrivilegesData>(
5349
...options,
5450
}
5551
)
52+
53+
export function invalidateTablePrivilegesQuery(
54+
client: QueryClient,
55+
projectRef: string | undefined
56+
) {
57+
return client.invalidateQueries(privilegeKeys.tablePrivilegesList(projectRef))
58+
}

apps/studio/data/privileges/table-privileges-revoke-mutation.ts

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
1+
import pgMeta from '@supabase/pg-meta'
12
import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query'
23
import { toast } from 'sonner'
34

4-
import type { components } from 'data/api'
5-
import { del, handleError } from 'data/fetchers'
5+
import { executeSql } from 'data/sql/execute-sql-query'
66
import type { ResponseError } from 'types'
7+
import { invalidateTablePrivilegesQuery } from './table-privileges-query'
78
import { privilegeKeys } from './keys'
89

9-
export type TablePrivilegesRevoke = components['schemas']['RevokeTablePrivilegesBody']
10+
export type TablePrivilegesRevoke = Parameters<
11+
typeof pgMeta.tablePrivileges.revoke
12+
>[0] extends (infer T)[]
13+
? T
14+
: never
1015

1116
export type TablePrivilegesRevokeVariables = {
1217
projectRef: string
@@ -19,21 +24,14 @@ export async function revokeTablePrivileges({
1924
connectionString,
2025
revokes,
2126
}: TablePrivilegesRevokeVariables) {
22-
const headers = new Headers()
23-
if (connectionString) headers.set('x-connection-encrypted', connectionString)
24-
25-
const { data, error } = await del('/platform/pg-meta/{ref}/table-privileges', {
26-
params: {
27-
path: { ref: projectRef },
28-
// this is needed to satisfy the typescript, but it doesn't pass the actual header
29-
header: { 'x-connection-encrypted': connectionString! },
30-
},
31-
body: revokes,
32-
headers,
27+
const sql = pgMeta.tablePrivileges.revoke(revokes).sql
28+
const { result } = await executeSql({
29+
projectRef,
30+
connectionString,
31+
sql,
32+
queryKey: ['table-privileges', 'revoke'],
3333
})
34-
35-
if (error) handleError(error)
36-
return data
34+
return result
3735
}
3836

3937
type TablePrivilegesRevokeData = Awaited<ReturnType<typeof revokeTablePrivileges>>
@@ -55,7 +53,7 @@ export const useTablePrivilegesRevokeMutation = ({
5553
const { projectRef } = variables
5654

5755
await Promise.all([
58-
queryClient.invalidateQueries(privilegeKeys.tablePrivilegesList(projectRef)),
56+
invalidateTablePrivilegesQuery(queryClient, projectRef),
5957
queryClient.invalidateQueries(privilegeKeys.columnPrivilegesList(projectRef)),
6058
])
6159

apps/studio/pages/api/pg-meta/[ref]/table-privileges.ts

Lines changed: 0 additions & 64 deletions
This file was deleted.

packages/pg-meta/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import roles from './pg-meta-roles'
22
import schemas from './pg-meta-schemas'
33
import * as functions from './pg-meta-functions'
4+
import tablePrivileges from './pg-meta-table-privileges'
45

56
export default {
67
roles,
78
schemas,
89
functions,
10+
tablePrivileges,
911
}

0 commit comments

Comments
 (0)