ExplainVisualizer.RowCountIndicator.tsx94 lines · main
1import { ArrowRight } from 'lucide-react'
2import { Tooltip, TooltipContent, TooltipTrigger } from 'ui'
3
4interface RowCountIndicatorProps {
5 actualRows?: number
6 estimatedRows?: number
7 rowsRemovedByFilter?: number
8}
9
10function formatRowCount(rows: number | undefined): string {
11 if (rows === undefined) return '-'
12 return rows.toLocaleString()
13}
14
15export function RowCountIndicator({
16 actualRows,
17 estimatedRows,
18 rowsRemovedByFilter,
19}: RowCountIndicatorProps) {
20 const hasActualRows = actualRows !== undefined
21 const hasEstimatedRows = estimatedRows !== undefined
22 const hasFilterData = rowsRemovedByFilter !== undefined && hasActualRows
23 const totalRowsScanned = hasFilterData ? actualRows + rowsRemovedByFilter : undefined
24
25 // Show filter flow: scanned → filtered out → remaining
26 if (hasFilterData && totalRowsScanned !== undefined) {
27 return (
28 <Tooltip>
29 <TooltipTrigger asChild>
30 <div className="flex items-center gap-1.5 cursor-help">
31 <span className="text-foreground-light">{formatRowCount(totalRowsScanned)}</span>
32 <ArrowRight size={10} className="text-foreground-muted" />
33 <span className="text-destructive-600 font-medium">
34 -{formatRowCount(rowsRemovedByFilter)}
35 </span>
36 <ArrowRight size={10} className="text-foreground-muted" />
37 <span className="text-brand font-medium">
38 {formatRowCount(actualRows)} {actualRows === 1 ? 'row' : 'rows'}
39 </span>
40 </div>
41 </TooltipTrigger>
42 <TooltipContent side="top" className="max-w-xs font-sans">
43 <p className="font-medium">Filter applied</p>
44 <p className="text-foreground-lighter text-xs mt-1">
45 {formatRowCount(totalRowsScanned)} rows were scanned,{' '}
46 {formatRowCount(rowsRemovedByFilter)} were filtered out, leaving{' '}
47 {formatRowCount(actualRows)} rows. Consider adding an index to reduce rows scanned.
48 </p>
49 </TooltipContent>
50 </Tooltip>
51 )
52 }
53
54 // Simple row count with actual rows
55 if (hasActualRows) {
56 return (
57 <Tooltip>
58 <TooltipTrigger asChild>
59 <span className="text-foreground-light cursor-help">
60 {formatRowCount(actualRows)} {actualRows === 1 ? 'row' : 'rows'}
61 </span>
62 </TooltipTrigger>
63 <TooltipContent side="top" className="max-w-xs font-sans">
64 <p className="font-medium">Rows returned</p>
65 <p className="text-foreground-lighter text-xs mt-1">
66 This operation processed and returned {formatRowCount(actualRows)} rows.
67 </p>
68 </TooltipContent>
69 </Tooltip>
70 )
71 }
72
73 // Only estimated rows available (EXPLAIN without ANALYZE)
74 if (hasEstimatedRows) {
75 return (
76 <Tooltip>
77 <TooltipTrigger asChild>
78 <span className="text-foreground-muted cursor-help">
79 est. {formatRowCount(estimatedRows)} {estimatedRows === 1 ? 'row' : 'rows'}
80 </span>
81 </TooltipTrigger>
82 <TooltipContent side="top" className="max-w-xs font-sans">
83 <p className="font-medium">Estimated rows</p>
84 <p className="text-foreground-lighter text-xs mt-1">
85 The planner estimates this operation will return {formatRowCount(estimatedRows)} rows.
86 Run with EXPLAIN ANALYZE to see actual row counts.
87 </p>
88 </TooltipContent>
89 </Tooltip>
90 )
91 }
92
93 return <span className="text-foreground-muted">-</span>
94}