diff --git a/src/reporters/github/github.test.ts b/src/reporters/github/github.test.ts index 79525bb..dbf41af 100644 --- a/src/reporters/github/github.test.ts +++ b/src/reporters/github/github.test.ts @@ -110,7 +110,7 @@ function makeContext(overrides: Partial = {}): ReportContext { statisticsMode: { kind: "fromAssumption", reltuples: 10000 }, recommendations: [], queriesPastThreshold: [], - queryStats: { total: 28, matched: 10, optimized: 2, errored: 0 }, + queryStats: { analyzed: 28, matched: 10, optimized: 2, errored: 0 }, statistics: [], metadata: { logSize: 1000, timeElapsed: 5000 }, ...overrides, @@ -323,18 +323,18 @@ describe("buildViewModel", () => { }); describe("template rendering", () => { - test("renders queryStats.total as the query count", () => { + test("renders queryStats.analyzed as the query count", () => { const ctx = makeContext({ - queryStats: { total: 5, matched: 3, optimized: 1, errored: 0 }, + queryStats: { analyzed: 5, matched: 3, optimized: 1, errored: 0 }, comparison: makeComparison(), }); const output = renderTemplate(ctx); expect(output).toContain("5 queries analyzed"); }); - test("renders queryStats.total in no-comparison mode", () => { + test("renders queryStats.analyzed in no-comparison mode", () => { const ctx = makeContext({ - queryStats: { total: 3, matched: 1, optimized: 0, errored: 0 }, + queryStats: { analyzed: 3, matched: 1, optimized: 0, errored: 0 }, }); const output = renderTemplate(ctx); expect(output).toContain("3 queries analyzed"); diff --git a/src/reporters/github/success.md.j2 b/src/reporters/github/success.md.j2 index 8e2d97c..0a30f60 100644 --- a/src/reporters/github/success.md.j2 +++ b/src/reporters/github/success.md.j2 @@ -4,10 +4,10 @@ {% endif %} {% if hasComparison %} -{{ queryStats.total | default('?') }} queries analyzed +{{ queryStats.analyzed | default('?') }} queries analyzed {%- if newQueryCount > 0 %} | {{ newQueryCount }} new quer{{ "ies" if newQueryCount != 1 else "y" }}{% endif %} {% else %} -{{ queryStats.total | default('?') }} queries analyzed — no baseline found to compare against. +{{ queryStats.analyzed | default('?') }} queries analyzed — no baseline found to compare against. > **No baseline on `{{ comparisonBranch }}`** — the analyzer cannot detect regressions without a previous run. To establish a baseline, add a `push` trigger for your comparison branch so the analyzer runs on merges to `{{ comparisonBranch }}`. See the [CI integration guide](https://docs.querydoctor.com/guides/ci-integration/#workflow-trigger) for setup instructions. {% endif %} diff --git a/src/reporters/reporter.ts b/src/reporters/reporter.ts index 8e55315..bebb16d 100644 --- a/src/reporters/reporter.ts +++ b/src/reporters/reporter.ts @@ -62,8 +62,8 @@ export type ReportMetadata = { declare const s: unique symbol; export interface ReportStatistics { - /** Number of unique, non-filtered queries analyzed */ - total: number; + /** Number of unique queries analyzed and uploaded to the site */ + analyzed: number; /** Number of queries that matched the query pattern */ matched: number; /** Number of queries that had an index recommendation */ diff --git a/src/runner.test.ts b/src/runner.test.ts new file mode 100644 index 0000000..0ddbe3b --- /dev/null +++ b/src/runner.test.ts @@ -0,0 +1,30 @@ +import { test, expect, describe } from "vitest"; +import { buildQueries } from "./reporters/site-api.ts"; +import type { OptimizedQuery } from "./sql/recent-query.ts"; + +function fakeQuery(hash: string, state: string): OptimizedQuery { + return { + hash, + query: "", + formattedQuery: "", + nudges: [], + tags: [], + tableReferences: [], + optimization: { state }, + } as unknown as OptimizedQuery; +} + +describe("queryStats.analyzed source of truth", () => { + test("buildQueries().length counts exactly the queries reported to the site", () => { + const results = [ + fakeQuery("a", "improvements_available"), + fakeQuery("b", "no_improvement_found"), + fakeQuery("c", "error"), + fakeQuery("d", "not_supported"), + fakeQuery("e", "timeout"), + fakeQuery("f", "waiting"), + fakeQuery("g", "optimizing"), + ]; + expect(buildQueries(results).length).toBe(3); + }); +}); diff --git a/src/runner.ts b/src/runner.ts index bc44d19..5afbb23 100644 --- a/src/runner.ts +++ b/src/runner.ts @@ -22,6 +22,7 @@ import { QueryHash } from "./sql/recent-query.ts"; import type { OptimizedQuery } from "./sql/recent-query.ts"; import { ExportedStats } from "@query-doctor/core"; import { readFile } from "node:fs/promises"; +import { buildQueries } from "./reporters/site-api.ts"; export class Runner { constructor( @@ -114,8 +115,6 @@ export class Runner { error = err; }); - let total = 0; - console.time("total"); const recentQueries: RecentQuery[] = []; for await (const chunk of stream) { @@ -164,7 +163,6 @@ export class Runner { continue; } - total++; const recentQuery = await RecentQuery.fromLogEntry(query, hash); recentQueries.push(recentQuery) } @@ -185,7 +183,7 @@ export class Runner { }); console.log( - `Matched ${this.remote.optimizer.validQueriesProcessed} queries out of ${total}`, + `Matched ${this.remote.optimizer.validQueriesProcessed} unique queries out of ${recentQueries.length} log entries`, ); const recommendations: ReportIndexRecommendation[] = []; @@ -250,6 +248,8 @@ export class Runner { } } + const analyzed = buildQueries(allResults, config).length; + const statistics = deriveIndexStatistics(filteredRecommendations); const timeElapsed = Date.now() - startDate.getTime(); const reportContext: ReportContext = { @@ -257,7 +257,7 @@ export class Runner { recommendations: filteredRecommendations, queriesPastThreshold: filteredThresholdWarnings, queryStats: Object.freeze({ - total, + analyzed, matched: this.remote.optimizer.validQueriesProcessed, optimized: filteredRecommendations.length, errored: optimizedQueries.filter((q) => q.optimization.state === "error").length,