Files
supabase/apps/studio/data/replication/publication-create-mutation.ts
Han Qiao 67deabf67e fix: create etl publication as postgres (#45043)
## What kind of change does this PR introduce?

Bug fix

## What is the current behavior?

Creating a schema only branch fails because ETL publication is owned by
`supabase_etl_admin` which users have no access.

## What is the new behavior?

Since ETL supports user managed publications, create them through pgmeta
so it's owned by `postgres` role instead.

## Additional context

mirrors [upstream
etl](https://github.com/supabase/etl/blob/main/etl-api/src/db/publications.rs#L22-L51)
implementation


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

* **Bug Fixes**
* Added guards to prevent creating publications when project or
connection info is missing, with clearer error logging.
* Ensure the project connection string is explicitly passed so
publications target the correct database.

* **Refactor**
* Publication creation now executes generated SQL directly against the
database, with correct handling of empty or selected table lists and
proper identifier quoting for reliability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
2026-04-27 19:45:26 +08:00

60 lines
1.8 KiB
TypeScript

import { getCreatePublicationSQL } from '@supabase/pg-meta'
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { toast } from 'sonner'
import { executeSql } from '../sql/execute-sql-query'
import { replicationKeys } from './keys'
import type { ResponseError, UseCustomMutationOptions } from '@/types'
export type CreatePublicationParams = {
projectRef: string
sourceId: number
name: string
tables: { schema: string; name: string }[]
connectionString?: string | null
}
async function createPublication(
{ projectRef, connectionString, name, tables }: CreatePublicationParams,
signal?: AbortSignal
) {
if (!projectRef) throw new Error('projectRef is required')
const sql = getCreatePublicationSQL({ name, tables })
const { result } = await executeSql({ projectRef, connectionString, sql }, signal)
return result
}
type CreatePublicationData = Awaited<ReturnType<typeof createPublication>>
export const useCreatePublicationMutation = ({
onSuccess,
onError,
...options
}: Omit<
UseCustomMutationOptions<CreatePublicationData, ResponseError, CreatePublicationParams>,
'mutationFn'
> = {}) => {
const queryClient = useQueryClient()
return useMutation<CreatePublicationData, ResponseError, CreatePublicationParams>({
mutationFn: (vars) => createPublication(vars),
async onSuccess(data, variables, context) {
const { projectRef, sourceId } = variables
await queryClient.invalidateQueries({
queryKey: replicationKeys.publications(projectRef, sourceId),
})
await onSuccess?.(data, variables, context)
},
async onError(data, variables, context) {
if (onError === undefined) {
toast.error(`Failed to create publication: ${data.message}`)
} else {
onError(data, variables, context)
}
},
...options,
})
}