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