Files

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),
}))
}