'use client'; import { Nudge } from "../sql/nudges.cjs"; import { LiveQueryOptimization } from "../query.cjs"; //#region src/findings/query-findings.d.ts /** * Plan-aware query findings. * * The *anti-pattern* nudges (parseNudges in ./sql/nudges.ts) are AST-only: they * read the SQL string and flag syntactic patterns, never the EXPLAIN plan — so * they can say "you put a function on a column" but not "…and that's why this * table is being sequentially scanned." (The nudge array can also carry * plan-derived *improvement* nudges — LARGE/SMALL_IMPROVEMENT_FOUND — but those * just report the optimizer's index gain as a number, not a plan-shape diagnosis.) * * This module fills that gap. Each finder is a pure function over data Query * Doctor already captures — the stored EXPLAIN plan plus the nudge array — and * emits a computed, human-readable verdict ("X is slow because Y"), not another * raw property for the UI to render. The output is deterministic: same plan in, * same findings out. */ type QueryFindingSeverity = "critical" | "warning" | "info"; type QueryFindingCode = "COST_CONCENTRATION" | "REPEATED_INNER_LOOP" | "EXPENSIVE_SEQ_SCAN" | "SORT_WITHOUT_INDEX" | "WIDE_RESULT_NO_LIMIT" | "FUNCTION_ON_COLUMN_BLOCKS_INDEX" | "FULL_TABLE_SCAN"; interface QueryFinding { code: QueryFindingCode; severity: QueryFindingSeverity; /** One-line headline, safe to show as a list item title. */ title: string; /** The "this is wrong because Y" sentence, in plain language. Only states what * the plan makes certain. */ detail: string; /** An optional, explicitly-conditional next step — a *lead*, not a fix. Used * when there's a plausible improvement we can't be sure of (it depends on the * data), so it's hedged: "often helps, verify before acting". Prescriptions * that we ARE sure of stay in `detail`. */ lead?: string; /** * Share of the query's cost this finding is worth fixing, 0–1. Mostly the * node's own cost share — but for a loop that's already its multiplied weight, * since Postgres folds the per-row repetition into the node's Total Cost; the * function-on-column finding scores by the *multiplied* cost of the scans it * blocks, and payload findings (not a cost share) get a size-derived score on * the same scale. Findings are returned sorted by it, so a reader attacks the * biggest lever first and isn't misled by a scary-but-tiny finding. */ impact: number; /** Structured backing for the claim — rendered as evidence chips. */ evidence?: Record; } /** * Compute the plan-aware findings for one query from its stored optimization and * nudges. Returns [] when there's no plan to reason over (waiting, optimizing, * not_supported, timeout, error) — the syntactic nudges still stand on their own. */ declare function analyzeQueryFindings(optimization: LiveQueryOptimization | undefined, nudges?: Nudge[]): QueryFinding[]; //#endregion export { QueryFinding, QueryFindingCode, QueryFindingSeverity, analyzeQueryFindings }; //# sourceMappingURL=query-findings.d.cts.map