Home / Function/ QueryDetail() — supabase Function Reference

QueryDetail() — supabase Function Reference

Architecture documentation for the QueryDetail() function in QueryDetail.tsx from the supabase codebase.

Entity Profile

Dependency Diagram

graph TD
  862166f4_4a42_1285_bc7d_cd62b193126e["QueryDetail()"]
  30f0a3ab_db83_7faa_cb69_e6f4d458b834["buildQueryExplanationPrompt()"]
  862166f4_4a42_1285_bc7d_cd62b193126e -->|calls| 30f0a3ab_db83_7faa_cb69_e6f4d458b834
  c766db49_5dcb_39c9_bf9f_6de30e40e28b["formatDuration()"]
  862166f4_4a42_1285_bc7d_cd62b193126e -->|calls| c766db49_5dcb_39c9_bf9f_6de30e40e28b
  style 862166f4_4a42_1285_bc7d_cd62b193126e fill:#6366f1,stroke:#818cf8,color:#fff

Relationship Graph

Source Code

apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx lines 36–259

export const QueryDetail = ({ selectedRow, onClickViewSuggestion, onClose }: QueryDetailProps) => {
  // [Joshen] TODO implement this logic once the linter rules are in
  const isLinterWarning = false
  const report = QUERY_PERFORMANCE_COLUMNS
  const [query, setQuery] = useState(selectedRow?.['query'])

  const { openSidebar } = useSidebarManagerSnapshot()
  const aiSnap = useAiAssistantStateSnapshot()
  const track = useTrack()

  const showExplainWithAiInQueryPerformance = useFlag('ShowExplainWithAiInQueryPerformance')

  useEffect(() => {
    if (selectedRow !== undefined) {
      const formattedQuery = formatSql(selectedRow['query'])
      setQuery(formattedQuery)
    }
  }, [selectedRow])

  const [isExpanded, setIsExpanded] = useState(false)

  const handleExplainQuery = () => {
    if (!selectedRow?.query) return

    const { query, prompt } = buildQueryExplanationPrompt(selectedRow)

    openSidebar(SIDEBAR_KEYS.AI_ASSISTANT)
    aiSnap.newChat({
      sqlSnippets: [
        {
          label: 'Query',
          content: query,
        },
      ],
      initialMessage: prompt,
    })

    track('query_performance_explain_with_ai_button_clicked')

    // Close the query detail panel since we need to see the AI assistant panel
    onClose?.()
  }

  const buildPromptForCopy = () => {
    if (!selectedRow?.query) return ''

    const { query, prompt } = buildQueryExplanationPrompt(selectedRow)
    return `${prompt}\n\nSQL Query:\n\`\`\`sql\n${query}\n\`\`\``
  }

  return (
    <QueryPanelContainer>
      <QueryPanelSection className="pt-2 border-b relative">
        <div className="flex items-center justify-between mb-4">
          <h4>Query pattern</h4>
          {showExplainWithAiInQueryPerformance && (
            <AiAssistantDropdown
              label="Explain with AI"
              buildPrompt={buildPromptForCopy}
              onOpenAssistant={handleExplainQuery}
              telemetrySource="query_performance"
              size="tiny"
              type="default"
            />
          )}
        </div>
        <div
          className={cn(
            'overflow-hidden pb-0 z-0 relative transition-all duration-300',
            isExpanded ? 'h-[348px]' : 'h-[120px]'
          )}
        >
          <SqlMonacoBlock
            value={query}
            height={322}
            lineNumbers="off"
            wrapperClassName={cn('pl-3 bg-surface-100', !isExpanded && 'pointer-events-none')}
          />
          {isLinterWarning && (
            <Alert_Shadcn_
              variant="default"
              className="mt-2 border-brand-400 bg-alternative [&>svg]:p-0.5 [&>svg]:bg-transparent [&>svg]:text-brand"
            >
              <Lightbulb />
              <AlertTitle_Shadcn_>Suggested optimization: Add an index</AlertTitle_Shadcn_>
              <AlertDescription_Shadcn_>
                Adding an index will help this query execute faster
              </AlertDescription_Shadcn_>
              <AlertDescription_Shadcn_>
                <Button className="mt-3" onClick={() => onClickViewSuggestion()}>
                  View suggestion
                </Button>
              </AlertDescription_Shadcn_>
            </Alert_Shadcn_>
          )}
        </div>
        <div
          className={cn(
            'absolute left-0 bottom-0 w-full bg-gradient-to-t from-black/30 to-transparent h-24 transition-opacity duration-300',
            isExpanded && 'opacity-0 pointer-events-none'
          )}
        />
        <div className="absolute -bottom-[13px] left-0 right-0 w-full flex items-center justify-center z-10">
          <Button
            type="default"
            className="rounded-full"
            icon={<ChevronsUpDown />}
            onClick={() => setIsExpanded(!isExpanded)}
          >
            {isExpanded ? 'Collapse' : 'Expand'}
          </Button>
        </div>
      </QueryPanelSection>
      <QueryPanelSection className="pb-3 pt-6">
        <h4 className="mb-2">Metadata</h4>
        <ul className="flex flex-col gap-y-3 divide-y divide-dashed">
          {report
            .filter((x) => x.id !== 'query')
            .map((x) => {
              const rawValue = selectedRow?.[x.id]
              const isTime = x.name.includes('time')

              const formattedValue = isTime
                ? typeof rawValue === 'number' && !isNaN(rawValue) && isFinite(rawValue)
                  ? `${Math.round(rawValue).toLocaleString()}ms`
                  : 'n/a'
                : rawValue != null
                  ? String(rawValue)
                  : 'n/a'

              if (x.id === 'prop_total_time') {
                const percentage = selectedRow?.prop_total_time || 0
                const totalTime = selectedRow?.total_time || 0

                return (
                  <li key={x.id} className="flex justify-between pt-3 text-sm">
                    <p className="text-foreground-light">{x.name}</p>
                    {percentage && totalTime ? (
                      <p className="flex items-center gap-x-1.5">
                        <span
                          className={cn(
                            'tabular-nums',
                            percentage.toFixed(1) === '0.0' && 'text-foreground-lighter'
                          )}
                        >
                          {percentage.toFixed(1)}%
                        </span>{' '}
                        <span className="text-muted">/</span>{' '}
                        <span
                          className={cn(
                            'tabular-nums',
                            formatDuration(totalTime) === '0.00s' && 'text-foreground-lighter'
                          )}
                        >
                          {formatDuration(totalTime)}
                        </span>
                      </p>
                    ) : (
                      <p className="text-muted">&ndash;</p>
                    )}
                  </li>
                )
              }

              if (x.id == 'rows_read') {
                return (
                  <li key={x.id} className="flex justify-between pt-3 text-sm">
                    <p className="text-foreground-light">{x.name}</p>
                    {typeof rawValue === 'number' && !isNaN(rawValue) && isFinite(rawValue) ? (
                      <p
                        className={cn('tabular-nums', rawValue === 0 && 'text-foreground-lighter')}
                      >
                        {rawValue.toLocaleString()}
                      </p>
                    ) : (
                      <p className="text-muted">&ndash;</p>
                    )}
                  </li>
                )
              }

              const cacheHitRateToNumber = (value: number | string) => {
                if (typeof value === 'number') return value
                return parseFloat(value.toString().replace('%', '')) || 0
              }

              if (x.id === 'cache_hit_rate') {
                return (
                  <li key={x.id} className="flex justify-between pt-3 text-sm">
                    <p className="text-foreground-light">{x.name}</p>
                    {typeof rawValue === 'string' || typeof rawValue === 'number' ? (
                      <p
                        className={cn(
                          cacheHitRateToNumber(rawValue).toFixed(2) === '0.00' &&
                            'text-foreground-lighter'
                        )}
                      >
                        {cacheHitRateToNumber(rawValue).toLocaleString(undefined, {
                          minimumFractionDigits: 2,
                          maximumFractionDigits: 2,
                        })}
                        %
                      </p>
                    ) : (
                      <p className="text-muted">&ndash;</p>
                    )}
                  </li>
                )
              }

              return (
                <li key={x.id} className="flex justify-between pt-3 text-sm">
                  <p className="text-foreground-light">{x.name}</p>
                  <p className={cn('tabular-nums', x.id === 'rolname' && 'font-mono')}>
                    {formattedValue}
                  </p>
                </li>
              )
            })}
        </ul>
      </QueryPanelSection>
    </QueryPanelContainer>
  )
}

Subdomains

Frequently Asked Questions

What does QueryDetail() do?
QueryDetail() is a function in the supabase codebase.
What does QueryDetail() call?
QueryDetail() calls 2 function(s): buildQueryExplanationPrompt, formatDuration.

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free