| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- // @ts-nocheck
- 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<void>
- }
- const TableIndexAdvisorContext = createContext<TableIndexAdvisorContextValue>({
- 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<TableIndexAdvisorProviderProps>) {
- const { data: project } = useSelectedProjectQuery()
- const { isIndexAdvisorAvailable, isIndexAdvisorEnabled } = useIndexAdvisorStatus()
- const queryClient = useQueryClient()
- const [isSheetOpen, setIsSheetOpen] = useState(false)
- const [selectedColumn, setSelectedColumn] = useState<string | undefined>(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 (
- <TableIndexAdvisorContext.Provider value={value}>
- {children}
- <Sheet open={isSheetOpen} onOpenChange={(open) => !open && closeSheet()}>
- <SheetContent className="flex flex-col gap-0 p-0 lg:w-[calc(100vw-802px)]! max-w-[700px]">
- <SheetHeader className="border-b px-5 py-3">
- <SheetTitle>Index Recommendation</SheetTitle>
- </SheetHeader>
- {selectedSuggestion && (
- <QueryIndexes
- selectedRow={{ query: selectedSuggestion.query }}
- columnName={selectedColumn}
- suggestedSelectQuery={selectedSuggestion.query}
- prefetchedIndexAdvisorResult={prefetchedIndexAdvisorResult}
- onClose={closeSheet}
- />
- )}
- </SheetContent>
- </Sheet>
- </TableIndexAdvisorContext.Provider>
- )
- }
- export function useTableIndexAdvisor() {
- return useContext(TableIndexAdvisorContext)
- }
- export function useColumnHasIndexSuggestion(columnName: string): boolean {
- const { columnsWithSuggestions } = useTableIndexAdvisor()
- return columnsWithSuggestions.includes(columnName)
- }
|