import { useQueryClient } from '@tanstack/react-query' import { createContext, PropsWithChildren, useCallback, useContext, useState } from 'react' import { Sheet, SheetContent, SheetHeader, SheetTitle } from 'ui' import { useIndexAdvisorStatus } from '@/components/interfaces/QueryPerformance/hooks/useIsIndexAdvisorStatus' import { QueryIndexes } from '@/components/interfaces/QueryPerformance/QueryIndexes' import { databaseKeys } from '@/data/database/keys' import { cleanIndexColumnName, IndexAdvisorSuggestion, TableIndexAdvisorData, useTableIndexAdvisorQuery, } from '@/data/database/table-index-advisor-query' import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' interface TableIndexAdvisorContextValue { isLoading: boolean isAvailable: boolean isEnabled: boolean columnsWithSuggestions: string[] suggestions: TableIndexAdvisorData['suggestions'] openSheet: (columnName: string) => void getSuggestionsForColumn: (columnName: string) => IndexAdvisorSuggestion[] invalidate: () => Promise } const TableIndexAdvisorContext = createContext({ isLoading: false, isAvailable: false, isEnabled: false, columnsWithSuggestions: [], suggestions: [], openSheet: () => {}, getSuggestionsForColumn: () => [], invalidate: async () => {}, }) interface TableIndexAdvisorProviderProps { schema: string table: string } export function TableIndexAdvisorProvider({ children, schema, table, }: PropsWithChildren) { const { data: project } = useSelectedProjectQuery() const { isIndexAdvisorAvailable, isIndexAdvisorEnabled } = useIndexAdvisorStatus() const queryClient = useQueryClient() const [isSheetOpen, setIsSheetOpen] = useState(false) const [selectedColumn, setSelectedColumn] = useState(undefined) const { data, isLoading } = useTableIndexAdvisorQuery( { projectRef: project?.ref, connectionString: project?.connectionString, schema, table, }, { enabled: isIndexAdvisorEnabled && !!schema && !!table, } ) const openSheet = useCallback((columnName: string) => { setSelectedColumn(columnName) setIsSheetOpen(true) }, []) const closeSheet = useCallback(() => { setIsSheetOpen(false) setSelectedColumn(undefined) }, []) const getSuggestionsForColumn = useCallback( (columnName: string): IndexAdvisorSuggestion[] => { if (!data?.suggestions) return [] // Filter suggestions that include this column in their index statements return data.suggestions.filter((suggestion) => suggestion.index_statements.some((stmt) => { const match = stmt.match(/USING\s+\w+\s*\(([^)]+)\)/i) if (match) { const columns = match[1].split(',').map((c) => cleanIndexColumnName(c)) return columns.includes(columnName) } return false }) ) }, [data?.suggestions] ) const invalidate = useCallback(async () => { if (project?.ref && schema && table) { await queryClient.invalidateQueries({ queryKey: databaseKeys.tableIndexAdvisor(project.ref, schema, table), }) } }, [queryClient, project?.ref, schema, table]) // Get the first suggestion for the selected column to pass to QueryIndexes const selectedSuggestion = selectedColumn ? getSuggestionsForColumn(selectedColumn)[0] : null const prefetchedIndexAdvisorResult = selectedSuggestion ? { errors: [], index_statements: selectedSuggestion.index_statements, startup_cost_before: selectedSuggestion.startup_cost_before, startup_cost_after: selectedSuggestion.startup_cost_after, total_cost_before: selectedSuggestion.total_cost_before, total_cost_after: selectedSuggestion.total_cost_after, } : null const value: TableIndexAdvisorContextValue = { isLoading, isAvailable: isIndexAdvisorAvailable, isEnabled: isIndexAdvisorEnabled, columnsWithSuggestions: data?.columnsWithSuggestions ?? [], suggestions: data?.suggestions ?? [], openSheet, getSuggestionsForColumn, invalidate, } return ( {children} !open && closeSheet()}> Index Recommendation {selectedSuggestion && ( )} ) } export function useTableIndexAdvisor() { return useContext(TableIndexAdvisorContext) } export function useColumnHasIndexSuggestion(columnName: string): boolean { const { columnsWithSuggestions } = useTableIndexAdvisor() return columnsWithSuggestions.includes(columnName) }