fix: move policy requests to query route (#35500)

This commit is contained in:
Han Qiao authored and GitHub committed 2025-05-12 23:54:46 +08:00
1 parent eafcc81df3
commit e2fddfeeeb
9 files changed
+77 -92

No files matched your search

@@ -110,7 +110,7 @@ const Policies = ({
deleteDatabasePolicy({
projectRef: project.ref,
connectionString: project.connectionString,
id: selectedPolicyToDelete.id,
originalPolicy: selectedPolicyToDelete,
})
}
@@ -225,9 +225,9 @@ export const PolicyEditorPanel = memo(function ({
if (Object.keys(payload).length === 0) return onSelectCancel()
updatePolicy({
id: selectedPolicy.id,
projectRef: selectedProject.ref,
connectionString: selectedProject?.connectionString,
originalPolicy: selectedPolicy,
payload,
})
}
@@ -52,7 +52,7 @@ const DeleteBucketModal = ({ visible = false, bucket, onClose }: DeleteBucketMod
deletePolicy({
projectRef: project?.ref,
connectionString: project?.connectionString,
id: policy.id,
originalPolicy: policy,
})
)
)
@@ -24,7 +24,7 @@ const StoragePolicies = () => {
const { data, isLoading: isLoadingBuckets } = useBucketsQuery({ projectRef })
const buckets = data ?? []
const [selectedPolicyToEdit, setSelectedPolicyToEdit] = useState({})
const [selectedPolicyToEdit, setSelectedPolicyToEdit] = useState<any>({})
const [selectedPolicyToDelete, setSelectedPolicyToDelete] = useState<any>({})
const [isEditingPolicyForBucket, setIsEditingPolicyForBucket] = useState<any>({})
@@ -155,7 +155,7 @@ const StoragePolicies = () => {
await updateDatabasePolicy({
projectRef: project?.ref,
connectionString: project?.connectionString,
id: payload.id,
originalPolicy: selectedPolicyToEdit,
payload,
})
return false
@@ -170,7 +170,7 @@ const StoragePolicies = () => {
deleteDatabasePolicy({
projectRef: project?.ref,
connectionString: project?.connectionString,
id: selectedPolicyToDelete.id,
originalPolicy: selectedPolicyToDelete,
})
}
@@ -1,8 +1,9 @@
import pgMeta from '@supabase/pg-meta'
import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query'
import { toast } from 'sonner'
import type { components } from 'data/api'
import { handleError, post } from 'data/fetchers'
import { executeSql } from 'data/sql/execute-sql-query'
import type { ResponseError } from 'types'
import { databasePoliciesKeys } from './keys'
@@ -22,17 +23,15 @@ export async function createDatabasePolicy({
let headers = new Headers()
if (connectionString) headers.set('x-connection-encrypted', connectionString)
const { data, error } = await post('/platform/pg-meta/{ref}/policies', {
params: {
header: { 'x-connection-encrypted': connectionString! },
path: { ref: projectRef },
},
body: payload,
headers,
const { sql } = pgMeta.policies.create(payload)
const { result } = await executeSql({
projectRef,
connectionString,
sql,
queryKey: ['policy', 'create'],
})
if (error) handleError(error)
return data
return result
}
type DatabasePolicyCreateData = Awaited<ReturnType<typeof createDatabasePolicy>>
@@ -1,35 +1,39 @@
import pgMeta from '@supabase/pg-meta'
import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query'
import { toast } from 'sonner'
import { del, handleError } from 'data/fetchers'
import { executeSql } from 'data/sql/execute-sql-query'
import type { ResponseError } from 'types'
import { databasePoliciesKeys } from './keys'
export type DatabasePolicyDeleteVariables = {
projectRef: string
connectionString?: string | null
id: number
originalPolicy: {
id: number
name: string
schema: string
table: string
}
}
export async function deleteDatabasePolicy({
projectRef,
connectionString,
id,
originalPolicy,
}: DatabasePolicyDeleteVariables) {
let headers = new Headers()
if (connectionString) headers.set('x-connection-encrypted', connectionString)
const { data, error } = await del('/platform/pg-meta/{ref}/policies', {
params: {
header: { 'x-connection-encrypted': connectionString! },
path: { ref: projectRef },
query: { id },
},
headers,
const { sql } = pgMeta.policies.remove(originalPolicy)
const { result } = await executeSql({
projectRef,
connectionString,
sql,
queryKey: ['policy', 'delete', originalPolicy.id],
})
if (error) handleError(error)
return data
return result
}
type DatabasePolicyDeleteData = Awaited<ReturnType<typeof deleteDatabasePolicy>>
@@ -1,14 +1,20 @@
import pgMeta from '@supabase/pg-meta'
import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query'
import { toast } from 'sonner'
import { handleError, patch } from 'data/fetchers'
import { executeSql } from 'data/sql/execute-sql-query'
import type { ResponseError } from 'types'
import { databasePoliciesKeys } from './keys'
export type DatabasePolicyUpdateVariables = {
projectRef: string
connectionString?: string | null
id: number
originalPolicy: {
id: number
name: string
schema: string
table: string
}
payload: {
name?: string
definition?: string
@@ -20,24 +26,21 @@ export type DatabasePolicyUpdateVariables = {
export async function updateDatabasePolicy({
projectRef,
connectionString,
id,
originalPolicy,
payload,
}: DatabasePolicyUpdateVariables) {
let headers = new Headers()
if (connectionString) headers.set('x-connection-encrypted', connectionString)
const { data, error } = await patch('/platform/pg-meta/{ref}/policies', {
params: {
header: { 'x-connection-encrypted': connectionString! },
path: { ref: projectRef },
query: { id },
},
body: payload,
headers,
const { sql } = pgMeta.policies.update(originalPolicy, payload)
const { result } = await executeSql({
projectRef,
connectionString,
sql,
queryKey: ['policy', 'update', originalPolicy.id],
})
if (error) handleError(error)
return data
return result
}
type DatabasePolicyUpdateData = Awaited<ReturnType<typeof updateDatabasePolicy>>
+17 -35
View File
@@ -128,46 +128,28 @@ type PolicyUpdateParams = {
roles?: string[]
}
function update(identifier: PolicyIdentifier, params: PolicyUpdateParams): { sql: string } {
function update(
identifier: Pick<PGPolicy, 'name' | 'schema' | 'table'>,
params: PolicyUpdateParams
): { sql: string } {
const { name, definition, check, roles } = params
const indentifyClause = getIdentifierWhereClause(identifier)
const sql = `
do $$
declare
old record;
begin
with policies as (${POLICIES_SQL})
select * into old from policies where ${indentifyClause};
if old is null then
raise exception 'Cannot find policy with id %', ${literal(indentifyClause)};
end if;
${definition ? `execute(format('alter policy %I on %I.%I using (%s);', old.name, old.schema, old.table, ${literal(definition)}));` : ''}
${check ? `execute(format('alter policy %I on %I.%I with check (%s);', old.name, old.schema, old.table, ${literal(check)}));` : ''}
${roles ? `execute(format('alter policy %I on %I.%I to %s;', old.name, old.schema, old.table, ${literal(roles.map(ident).join(','))}));` : ''}
${name ? `execute(format('alter policy %I on %I.%I rename to %I;', old.name, old.schema, old.table, ${literal(name)}));` : ''}
end
$$;`
const alter = `ALTER POLICY ${ident(identifier.name)} ON ${ident(identifier.schema)}.${ident(identifier.table)}`
const nameSql = name === undefined ? '' : `${alter} RENAME TO ${ident(name)};`
const definitionSql = definition === undefined ? '' : `${alter} USING (${definition});`
const checkSql = check === undefined ? '' : `${alter} WITH CHECK (${check});`
const rolesSql = roles === undefined ? '' : `${alter} TO ${roles.map(ident).join(',')};`
// nameSql must be last
const sql = `BEGIN; ${definitionSql} ${checkSql} ${rolesSql} ${nameSql} COMMIT;`
return { sql }
}
function remove(identifier: PolicyIdentifier): { sql: string } {
const indentifyClause = getIdentifierWhereClause(identifier)
const sql = `
do $$
declare
old record;
begin
with policies as (${POLICIES_SQL})
select * into old from policies where ${indentifyClause};
if old is null then
raise exception 'Cannot find policy with id %', ${literal(indentifyClause)};
end if;
execute(format('drop policy %I on %I.%I;', old.name, old.schema, old.table));
end
$$;`
function remove(identifier: Pick<PGPolicy, 'name' | 'schema' | 'table'>): { sql: string } {
const sql = `DROP POLICY ${ident(identifier.name)} ON ${ident(identifier.schema)}.${ident(
identifier.table
)};`
return { sql }
}
+13 -16
View File
@@ -22,7 +22,7 @@ const withTestDatabase = (
}
withTestDatabase('list policies', async ({ executeQuery }) => {
const { sql, zod } = await pgMeta.policies.list()
const { sql, zod } = pgMeta.policies.list()
const res = zod.parse(await executeQuery(sql))
const policy = res.find(({ name }) => name === 'categories_update_policy')
@@ -48,7 +48,7 @@ withTestDatabase('list policies', async ({ executeQuery }) => {
})
withTestDatabase('list policies with included schemas', async ({ executeQuery }) => {
const { sql, zod } = await pgMeta.policies.list({
const { sql, zod } = pgMeta.policies.list({
includedSchemas: ['public'],
})
const res = zod.parse(await executeQuery(sql))
@@ -61,7 +61,7 @@ withTestDatabase('list policies with included schemas', async ({ executeQuery })
withTestDatabase('retrieve, create, update, delete policies', async ({ executeQuery }) => {
// Create policy
const { sql: createSql } = await pgMeta.policies.create({
const { sql: createSql } = pgMeta.policies.create({
name: 'test_policy',
schema: 'public',
table: 'memes',
@@ -70,7 +70,7 @@ withTestDatabase('retrieve, create, update, delete policies', async ({ executeQu
await executeQuery(createSql)
// List to get the created policy
const { sql: listSql, zod: listZod } = await pgMeta.policies.list()
const { sql: listSql, zod: listZod } = pgMeta.policies.list()
const policies = listZod.parse(await executeQuery(listSql))
const createdPolicy = policies.find((p) => p.name === 'test_policy')
@@ -95,19 +95,16 @@ withTestDatabase('retrieve, create, update, delete policies', async ({ executeQu
)
// Update policy
const { sql: updateSql } = await pgMeta.policies.update(
{ id: createdPolicy!.id },
{
name: 'updated_policy',
definition: "current_setting('my.username') IN (name)",
check: "current_setting('my.username') IN (name)",
roles: ['postgres'],
}
)
const { sql: updateSql } = pgMeta.policies.update(createdPolicy!, {
name: 'updated_policy',
definition: "current_setting('my.username') IN (name)",
check: "current_setting('my.username') IN (name)",
roles: ['postgres'],
})
await executeQuery(updateSql)
// Retrieve updated policy
const { sql: retrieveSql, zod: retrieveZod } = await pgMeta.policies.retrieve({
const { sql: retrieveSql, zod: retrieveZod } = pgMeta.policies.retrieve({
id: createdPolicy!.id,
})
const updatedPolicy = retrieveZod.parse((await executeQuery(retrieveSql))[0])
@@ -133,11 +130,11 @@ withTestDatabase('retrieve, create, update, delete policies', async ({ executeQu
)
// Remove policy
const { sql: removeSql } = await pgMeta.policies.remove({ id: updatedPolicy!.id })
const { sql: removeSql } = pgMeta.policies.remove(updatedPolicy!)
await executeQuery(removeSql)
// Verify policy is removed
const { sql: verifyRemoveSql } = await pgMeta.policies.retrieve({
const { sql: verifyRemoveSql } = pgMeta.policies.retrieve({
id: updatedPolicy!.id,
})
const result = await executeQuery(verifyRemoveSql)