@dudousxd/nestjs-telescope
Version:
Laravel Telescope-style observability console for NestJS — core: watchers, recorder, correlation, SQLite store, headless API.
64 lines • 3.19 kB
TypeScript
import { type Entry } from '../entry/entry.js';
/**
* A detected N+1 LOOP pattern within a single batch: one driving "parent" query
* (the SELECT that produced the rows being iterated) followed by N similarly-
* shaped "child" queries (the per-row lookups). Richer than the flat
* {@link detectNPlusOne} family-count: it attributes a likely parent and weights
* by the total time WASTED in the loop, so the worst offenders rank first.
*/
export interface NPlusOnePattern {
/** The repeated child query's family hash. */
childFamilyHash: string;
/** A representative child SQL (template/text). */
childSql: string;
/** How many times the child query ran in the batch (>= threshold). */
count: number;
/** Sum of the child queries' durations (ms) — the "wasted" time, the rank key. */
totalDurationMs: number;
/**
* The family hash of the query that most likely drove the loop — the distinct
* query immediately preceding the loop in record order — or `null` when the
* loop is the first thing in the batch (no identifiable parent).
*/
parentFamilyHash: string | null;
/** The likely-parent SQL, or `null` when there is no identifiable parent. */
parentSql: string | null;
/** A representative child entry id (deep-link / hydration seam). */
representativeId: string;
/** The batch the pattern was found in. */
batchId: string;
}
export interface NPlusOnePatternOptions {
/** Minimum repetitions of one child template to flag a loop. */
threshold: number;
}
/**
* Detect N+1 loop patterns in a batch's query entries. For each query family that
* repeats `>= threshold` times, we emit a pattern weighted by the loop's total
* duration and attribute the likely driving parent (the distinct query that ran
* just before the loop began). Pure; ordered by total wasted duration desc.
*
* DESIGN: the flat {@link detectNPlusOne} only answers "did family X repeat N
* times". This adds the two things that make an N+1 actionable — *which* query
* caused it, and *how much time* it cost — modelled on how Sentry/Laravel
* surface N+1: the loop body plus the originating parent span, ranked by cost.
*/
export declare function detectNPlusOnePatterns(entries: Entry[], options: NPlusOnePatternOptions): NPlusOnePattern[];
/** The content shape of a synthetic N+1 insight entry (see {@link toSyntheticInsightEntry}). */
export interface NPlusOneInsightContent {
kind: 'n-plus-one';
childSql: string;
parentSql: string | null;
count: number;
totalDurationMs: number;
message: string;
}
/**
* Convert a detected pattern into a SYNTHETIC insight entry so the loop surfaces
* in the same entry stream as everything else (deep-linked to its batch). It is
* NOT a captured event — `id` is derived deterministically from the batch +
* child family so re-running detection over the same batch yields a stable id
* (idempotent ingestion). Carries the `n-plus-one` + `insight` tags for filtering.
*/
export declare function toSyntheticInsightEntry(pattern: NPlusOnePattern, at?: Date): Entry<NPlusOneInsightContent>;
//# sourceMappingURL=n-plus-one-pattern.d.ts.map