Files
supabase/apps/studio/data/sql/use-execute-sql-editor-query.ts
Jordi EnricandClaude Opus 4.8 2f102bedce feat(studio): foundation for a Logs source in the SQL Editor
Adds the logs source sentinel + helpers (default 24h range, AI schema context)
and useExecuteSQLEditorQuery, which routes the editor's execute call to Postgres
or the ClickHouse logs endpoint behind one mutation-shaped interface.

Not wired into the editor UI yet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 13:26:07 +02:00

86 lines
2.9 KiB
TypeScript

import { useMutation } from '@tanstack/react-query'
import { isLogsSource } from '@/components/interfaces/SQLEditor/sqlEditorLogs'
import { get, handleError } from '@/data/fetchers'
import { logsAllEndpointUrl } from '@/data/logs/logs-endpoint'
import { useExecuteSqlMutation } from '@/data/sql/execute-sql-mutation'
/**
* Variables accepted by the SQL Editor's execute call. Extends the Postgres
* mutation variables with the selected `source` and a time range, which the logs
* source needs and Postgres ignores.
*/
export type ExecuteSQLEditorVariables = {
projectRef?: string
connectionString?: string | null
sql: any
source?: string
iso_timestamp_start?: string
iso_timestamp_end?: string
autoLimit?: number
isRoleImpersonationEnabled?: boolean
isStatementTimeoutDisabled?: boolean
contextualInvalidation?: boolean
handleError?: (error: any) => { result: any }
}
type ExecuteSQLEditorOptions = {
onSuccess?: (data: { result: any }, variables: ExecuteSQLEditorVariables) => void
onError?: (error: any, variables: ExecuteSQLEditorVariables) => void
}
// Runs user-typed SQL against the ClickHouse-backed logs endpoint. Mirrors the
// Logs Explorer: the query goes through as a plain string (user-authored SQL is
// trusted) and the result rows come back under `result`.
async function executeLogsQuery(variables: ExecuteSQLEditorVariables) {
const { projectRef, sql, iso_timestamp_start, iso_timestamp_end } = variables
if (!projectRef) throw new Error('projectRef is required')
const { data, error } = await get(logsAllEndpointUrl(true), {
params: {
path: { ref: projectRef },
query: {
sql: sql as string,
iso_timestamp_start: iso_timestamp_start ?? '',
iso_timestamp_end: iso_timestamp_end ?? '',
},
},
})
if (error) handleError(error)
if (data?.error) {
throw new Error(typeof data.error === 'string' ? data.error : 'Failed to query logs')
}
return { result: data?.result ?? [] }
}
/**
* SQL Editor execution router. Runs the query against Postgres by default, or
* against the logs endpoint when the selected source is the logs pseudo-source.
* Both paths resolve through the same `{ result }` shape so the editor's success
* and error handlers stay unchanged.
*/
export function useExecuteSQLEditorQuery(options: ExecuteSQLEditorOptions = {}) {
const { onSuccess, onError } = options
const pgMutation = useExecuteSqlMutation({
onSuccess: onSuccess as any,
onError: onError as any,
})
const logsMutation = useMutation({
mutationFn: executeLogsQuery,
onSuccess: (data, variables) => onSuccess?.(data, variables),
onError: (error, variables) => onError?.(error, variables),
})
const mutate = (variables: ExecuteSQLEditorVariables) => {
if (isLogsSource(variables.source)) {
logsMutation.mutate(variables)
} else {
pgMutation.mutate(variables as any)
}
}
return { mutate, isPending: pgMutation.isPending || logsMutation.isPending }
}