mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 01:45:10 +03:00
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
63 lines
2.4 KiB
TypeScript
63 lines
2.4 KiB
TypeScript
import { useQueries } from '@tanstack/react-query'
|
|
|
|
import { useIndexAdvisorStatus } from '../../QueryPerformance/hooks/useIsIndexAdvisorStatus'
|
|
import type { QueryPerformanceRow } from '../../QueryPerformance/QueryPerformance.types'
|
|
import { databaseKeys } from '@/data/database/keys'
|
|
import { getIndexAdvisorResult } from '@/data/database/retrieve-index-advisor-result-query'
|
|
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
|
|
|
|
function isEligibleQuery(query: string): boolean {
|
|
const lower = query.trim().toLowerCase()
|
|
if (!lower.startsWith('select') && !lower.startsWith('with')) return false
|
|
// Dollar-quoted string literals (e.g. $$...$$ or $tag$...$tag$) break the single-quoted
|
|
// SQL embedding in getIndexAdvisorResult. Plain parameter markers ($1, $2, …) are fine.
|
|
if (/\$([A-Za-z_][A-Za-z0-9_]*)?\$/.test(query)) return false
|
|
return true
|
|
}
|
|
|
|
export function useSupamonitorIndexAdvisor(rows: QueryPerformanceRow[]): QueryPerformanceRow[] {
|
|
const { data: project } = useSelectedProjectQuery()
|
|
const { isIndexAdvisorEnabled } = useIndexAdvisorStatus()
|
|
|
|
const eligibleQueries = rows.map((r) => r.query).filter(isEligibleQuery)
|
|
|
|
const results = useQueries({
|
|
queries: eligibleQueries.map((query) => ({
|
|
queryKey: databaseKeys.indexAdvisorFromQuery(
|
|
project?.ref,
|
|
query,
|
|
project?.connectionString ?? undefined
|
|
),
|
|
queryFn: () =>
|
|
getIndexAdvisorResult({
|
|
projectRef: project?.ref,
|
|
connectionString: project?.connectionString,
|
|
query,
|
|
}),
|
|
enabled: isIndexAdvisorEnabled && !!project?.ref,
|
|
retry: false,
|
|
staleTime: Infinity,
|
|
})),
|
|
})
|
|
|
|
if (!isIndexAdvisorEnabled) return rows
|
|
|
|
const resultByQuery = new Map(
|
|
eligibleQueries.map((query, i) => {
|
|
const result = results[i]
|
|
// Only treat as ready when status is definitively success or error.
|
|
// undefined/pending means data hasn't arrived yet — store undefined so
|
|
// classifyQuery can defer slow classification and avoid flicker.
|
|
const isReady = result?.status === 'success' || result?.status === 'error'
|
|
return [query, isReady ? (result.data ?? null) : undefined]
|
|
})
|
|
)
|
|
|
|
return rows.map((row) => ({
|
|
...row,
|
|
index_advisor_result: resultByQuery.has(row.query)
|
|
? resultByQuery.get(row.query)
|
|
: (row.index_advisor_result ?? null),
|
|
}))
|
|
}
|