Skip to content

Commit c66e0ef

Browse files
committed
docs/samples: consolidate quickstart+budgets+wiring in root README; add package READMEs; fix samples NuGet path; de-duplicate sample docs
1 parent 8add0b4 commit c66e0ef

File tree

8 files changed

+186
-209
lines changed

8 files changed

+186
-209
lines changed

.github/workflows/samples-ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ jobs:
4242
run: dotnet pack ./src/KeelMatrix.QueryWatch/KeelMatrix.QueryWatch.csproj -c Release --no-build --include-symbols --p:SymbolPackageFormat=snupkg --output ./artifacts/packages
4343
- name: Pack QueryWatch.EfCore
4444
run: dotnet pack ./src/KeelMatrix.QueryWatch.EfCore/KeelMatrix.QueryWatch.EfCore.csproj -c Release --no-build --include-symbols --p:SymbolPackageFormat=snupkg --output ./artifacts/packages
45+
- name: Build QueryWatch.Redaction (Release)
46+
run: dotnet build ./src/KeelMatrix.QueryWatch.Redaction/KeelMatrix.QueryWatch.Redaction.csproj -c Release --no-restore
47+
- name: Pack QueryWatch.Redaction
48+
run: dotnet pack ./src/KeelMatrix.QueryWatch.Redaction/KeelMatrix.QueryWatch.Redaction.csproj -c Release --no-build --include-symbols --p:SymbolPackageFormat=snupkg --output ./artifacts/packages
4549

4650
# 3) Restore samples using their NuGet.config (pins KeelMatrix.QueryWatch* to ../artifacts/packages)
4751
- name: Restore samples

README.md

Lines changed: 117 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,133 @@
1-
> The project is currently under development. Keep an eye out for its release!
1+
# QueryWatch
22

3-
# KeelMatrix.QueryWatch
3+
Guardrail your **database queries** in tests & CI. Capture executed SQL, enforce **budgets** (counts & timings), and fail builds on regressions. Works with **ADO.NET**, **Dapper**, and **EF Core**.
44

5-
> Catch N+1 queries and slow SQL in tests. Fail builds when query budgets are exceeded.
5+
**Quick links:**
6+
- 👉 [Quick Start — Samples (local)](#quick-start--samples-local)
7+
- 👉 [EF Core wiring](#ef-core-wiring) · [Dapper wiring](#dapper-wiring) · [ADO.NET wiring](#adonet-wiring)
8+
- 👉 [CLI flags](#cli) · [Troubleshooting](#troubleshooting)
69

7-
[![Build](https://github.com/OWNER/REPO/actions/workflows/ci.yml/badge.svg)](https://github.com/OWNER/REPO/actions/workflows/ci.yml) [![NuGet](https://img.shields.io/nuget/v/KeelMatrix.QueryWatch.svg)](https://www.nuget.org/packages/KeelMatrix.QueryWatch/)
10+
---
811

9-
## Install
12+
## 5‑minute success (tests)
1013

11-
```bash
12-
dotnet add package KeelMatrix.QueryWatch
13-
# EF Core users:
14-
dotnet add package KeelMatrix.QueryWatch.EfCore
15-
```
16-
17-
## 5‑minute success (with JSON for CI)
18-
19-
**Per‑test scope → export JSON:**
14+
Use the disposable scope to **export JSON** and enforce **budgets** in your test or smoke app.
2015

2116
```csharp
2217
using KeelMatrix.QueryWatch.Testing;
2318

24-
// JSON is written even if assertions fail (helps CI).
25-
using var q = QueryWatchScope.Start(
26-
maxQueries: 5,
27-
maxAverage: TimeSpan.FromMilliseconds(50),
19+
using var scope = QueryWatchScope.Start(
20+
maxQueries: 50,
21+
maxAverage: TimeSpan.FromMilliseconds(25),
2822
exportJsonPath: "artifacts/qwatch.report.json",
29-
sampleTop: 50); // increase if you plan to use per‑pattern budgets in CLI
23+
sampleTop: 200);
24+
25+
// ... run your code that hits the DB ...
3026
```
3127

32-
**Gate in CI (already wired in ci.yml):**
28+
The file `artifacts/qwatch.report.json` is now ready for the CLI gate.
3329

34-
```pwsh
35-
dotnet run --project tools/KeelMatrix.QueryWatch.Cli -- --input artifacts/qwatch.report.json --max-queries 50
36-
```
30+
---
31+
32+
## Quick Start — Samples (local)
33+
34+
This repo ships three tiny sample apps (EF Core, ADO.NET, Dapper) that **consume local packages** you build from source.
35+
36+
1. **Pack the libraries** (run **at repo root**):
37+
```bash
38+
dotnet pack ./src/KeelMatrix.QueryWatch/KeelMatrix.QueryWatch.csproj -c Release --include-symbols --p:SymbolPackageFormat=snupkg --output ./artifacts/packages
39+
dotnet pack ./src/KeelMatrix.QueryWatch.EfCore/KeelMatrix.QueryWatch.EfCore.csproj -c Release --include-symbols --p:SymbolPackageFormat=snupkg --output ./artifacts/packages
40+
```
41+
2. **Install local packages to samples** (pins to `./artifacts/packages` via `samples/NuGet.config`):
42+
- Windows (PowerShell): `./samples/init.ps1`
43+
- Linux/macOS (bash): `./samples/init.sh`
44+
3. **Run a sample** (EF example shown):
45+
```bash
46+
dotnet run --project ./samples/EFCore.Sqlite/EFCore.Sqlite.csproj -c Release
47+
```
48+
4. **Gate with the CLI**:
49+
```bash
50+
dotnet run --project ./tools/KeelMatrix.QueryWatch.Cli -- --input ./samples/EFCore.Sqlite/bin/Release/net8.0/artifacts/qwatch.ef.json --max-queries 50
51+
```
52+
53+
> CI uses the same flow and restores using `samples/NuGet.config` so **samples build after `dotnet pack` with no tweaks**.
54+
55+
---
3756

3857
## EF Core wiring
3958

4059
```csharp
41-
using KeelMatrix.QueryWatch.EfCore; // extension lives in the EfCore adapter package
4260
using Microsoft.EntityFrameworkCore;
61+
using KeelMatrix.QueryWatch.EfCore;
62+
using KeelMatrix.QueryWatch.Testing;
63+
64+
using var q = QueryWatchScope.Start(exportJsonPath: "artifacts/ef.json", sampleTop: 200);
4365

4466
var options = new DbContextOptionsBuilder<MyDbContext>()
4567
.UseSqlite("Data Source=:memory:")
4668
.UseQueryWatch(q.Session) // adds the interceptor
4769
.Options;
4870
```
71+
> Interceptor only records **executed** commands. Use `QueryWatchOptions` on the session to tune capture (text, parameter shapes, etc.).
72+
73+
---
74+
75+
## Dapper wiring
76+
77+
```csharp
78+
using Dapper;
79+
using Microsoft.Data.Sqlite;
80+
using KeelMatrix.QueryWatch.Dapper;
81+
using KeelMatrix.QueryWatch.Testing;
82+
83+
using var q = QueryWatchScope.Start(exportJsonPath: "artifacts/dapper.json", sampleTop: 200);
84+
85+
await using var raw = new SqliteConnection("Data Source=:memory:");
86+
await raw.OpenAsync();
87+
88+
// Wrap the provider connection so Dapper commands are recorded
89+
using var conn = raw.WithQueryWatch(q.Session);
90+
91+
var rows = await conn.QueryAsync("SELECT 1");
92+
```
93+
94+
> The extension returns the **ADO wrapper** when possible for high‑fidelity recording; otherwise it falls back to a Dapper‑specific wrapper.
95+
96+
---
97+
98+
## ADO.NET wiring
99+
100+
```csharp
101+
using Microsoft.Data.Sqlite;
102+
using KeelMatrix.QueryWatch.Ado;
103+
using KeelMatrix.QueryWatch.Testing;
104+
105+
using var q = QueryWatchScope.Start(exportJsonPath: "artifacts/ado.json", sampleTop: 200);
106+
await using var raw = new SqliteConnection("Data Source=:memory:");
107+
await raw.OpenAsync();
108+
109+
using var conn = new QueryWatchConnection(raw, q.Session);
110+
using var cmd = conn.CreateCommand();
111+
cmd.CommandText = "SELECT 1";
112+
await cmd.ExecuteNonQueryAsync();
113+
```
114+
115+
---
116+
117+
## Budgets (counts & timing)
118+
119+
At **test time** (scope) you can enforce `maxQueries`, `maxAverage`, `maxTotal`. At **CI time** use the CLI for stronger rules including **per‑pattern budgets**. Patterns support wildcards (`*`, `?`) or `regex:` prefix.
120+
121+
Example per‑pattern budgets:
122+
123+
```bash
124+
--budget "SELECT * FROM Users*=1"
125+
--budget "regex:^UPDATE Orders SET=3"
126+
```
127+
128+
> If your JSON is **top‑N sampled**, budgets evaluate only over those events. Increase `sampleTop` in your export to tighten guarantees.
129+
130+
---
49131

50132
## CLI
51133

@@ -67,40 +149,22 @@ var options = new DbContextOptionsBuilder<MyDbContext>()
67149
<!-- END:CLI_FLAGS -->
68150

69151
### Multi‑file support
70-
71152
Repeat `--input` to aggregate multiple JSONs (e.g., per‑project reports in a mono‑repo). Budgets evaluate on the aggregate.
72153

73154
### GitHub PR summary
155+
When run inside GitHub Actions, the CLI writes a Markdown table to the **Step Summary** automatically.
74156

75-
When run inside GitHub Actions, the CLI writes a Markdown table to the **Step Summary** automatically, so reviewers see metrics and any violations at a glance.
76-
77-
### Note on per‑pattern budgets
78-
79-
Budgets match against the `events` captured in the JSON file(s). These are the top‑N slowest events by duration to keep files small. If you want strict coverage, export with a higher `sampleTop` in `QueryWatchJson.ExportToFile`, or pass a larger `sampleTop` to `QueryWatchScope.Start(...)`.
80-
81-
## Redactor ordering tips
82-
83-
If you use multiple redactors, **order matters**. A safe, effective default is:
84-
85-
1. **Whitespace normalizer** – make SQL text stable across environments/providers.
86-
2. **High‑entropy token masks** – long hex tokens, JWTs, API keys.
87-
3. **PII masks** – emails, phone numbers, IPs.
88-
4. **Custom rules** – your app–specific patterns (use `AddRegexRedactor(...)`).
89-
90-
> Put *broad* rules (like whitespace) first, and *specific* rules (like PII) after. This lowers the chance one rule prevents another from matching.
91-
92-
## Typical budgets for Dapper‑heavy solutions
93-
94-
Dapper often issues *fewer, more targeted* commands than ORMs. Reasonable starting points (tune per project):
157+
---
95158

96-
- **End‑to‑end web test:** `--max-queries 40`, `--max-average-ms 50`, `--max-total-ms 1500`.
97-
- **Repository‑level test:** `--max-queries 10`, `--max-average-ms 25`, `--max-total-ms 250`.
98-
- **Per‑pattern budgets:** cap hot spots explicitly, e.g.:
159+
## Troubleshooting
99160

100-
```
101-
--budget "SELECT * FROM Users*=5" --budget "regex:^UPDATE Orders SET=3"
102-
```
161+
- **“Budget violations:” but no pattern table** → you didn’t pass any `--budget`, or your JSON was **heavily sampled**. Re‑export with higher `sampleTop` (e.g., 200–500).
162+
- **Baselines seem too strict** → tolerances are **percent of baseline**. Ensure your baseline is representative; use `--baseline-allow-percent` to allow small drift.
163+
- **CLI help in README looks stale** → run `./build/Update-ReadmeFlags.ps1` (or `--print-flags-md`) to refresh the block between markers.
164+
- **Hot path text capture** → disable per‑adapter: `QueryWatchOptions.Disable{Ado|Dapper|EfCore}TextCapture=true`.
165+
- **Parameter metadata** → set `QueryWatchOptions.CaptureParameterShape=true` (emits `event.meta.parameters`), never values.
103166

104-
- Increase `sampleTop` in code (`QueryWatchScope.Start(..., sampleTop: 200)`) if you rely on many per‑pattern budgets.
167+
---
105168

106-
Treat these as **guardrails**: keep design flexible but catch accidental N+1s or slow queries early.
169+
## License
170+
MIT

samples/README.md

Lines changed: 13 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,22 @@
11
# QueryWatch Samples
22

3-
This folder contains small **sample projects** that consume the `KeelMatrix.QueryWatch` NuGet package
4-
from your local build. They are intentionally minimal so you can understand and test the core behaviors
5-
quickly in different situations (EF Core + SQLite, and raw ADO).
6-
7-
> **Important:** These samples expect you to build the package(s) locally first and then add them to each sample.
8-
> See the "Quick Start" below.
3+
Tiny apps that consume the local `KeelMatrix.QueryWatch*` packages so you can see EF Core, ADO.NET, and Dapper wiring in action.
94

105
## Layout
11-
- `EFCore.Sqlite/` – EF Core (SQLite provider) showing interceptor wiring and basic budgets.
12-
- `Ado.Sqlite/` – plain ADO.NET over `Microsoft.Data.Sqlite` wrapped by `QueryWatchConnection`.
13-
- `Dapper.Sqlite/` – tiny Dapper example over SQLite showing **async** and **transaction** usage with QueryWatch.
14-
- `cli-examples.ps1` / `cli-examples.sh` – example commands for running the QueryWatch CLI gate.
15-
- `NuGet.config` – forces the `KeelMatrix.QueryWatch*` packages to come from your local `../artifacts/packages`.
16-
- `.gitignore` – ignores local build outputs and DB files for samples only.
6+
- `EFCore.Sqlite/` – EF Core (SQLite) with interceptor wiring and basic budgets.
7+
- `Ado.Sqlite/` – plain ADO.NET over `Microsoft.Data.Sqlite` via `QueryWatchConnection`.
8+
- `Dapper.Sqlite/` – Dapper (async + transactions) via `WithQueryWatch(...)`.
9+
- `cli-examples.ps1` / `cli-examples.sh` – quick commands to run the CLI gate.
10+
- `NuGet.config` – pins `KeelMatrix.QueryWatch*` to `../artifacts/packages` (local build).
1711

18-
## Quick Start (local, step-by-step)
19-
1. **Pack the libraries** at the repository root (one level *above* this folder):
20-
```bash
21-
dotnet pack ./src/KeelMatrix.QueryWatch/KeelMatrix.QueryWatch.csproj -c Release --include-symbols --p:SymbolPackageFormat=snupkg --output ./artifacts/packages
22-
dotnet pack ./src/KeelMatrix.QueryWatch.EfCore/KeelMatrix.QueryWatch.EfCore.csproj -c Release --include-symbols --p:SymbolPackageFormat=snupkg --output ./artifacts/packages
23-
```
24-
2. **Install the packages into each sample** (runs the add+restore for you):
25-
- Windows (PowerShell): `./init.ps1`
26-
- Linux/macOS (bash): `./init.sh`
27-
These scripts run:
28-
```bash
29-
dotnet add ./EFCore.Sqlite/EFCore.Sqlite.csproj package KeelMatrix.QueryWatch
30-
dotnet add ./EFCore.Sqlite/EFCore.Sqlite.csproj package KeelMatrix.QueryWatch.EfCore
31-
dotnet add ./Ado.Sqlite/Ado.Sqlite.csproj package KeelMatrix.QueryWatch
32-
```
33-
The included `NuGet.config` pins `KeelMatrix.QueryWatch*` to the local `../artifacts/packages` folder.
34-
3. **Run a sample** (EF Core example shown):
35-
```bash
36-
dotnet run --project ./EFCore.Sqlite/EFCore.Sqlite.csproj
37-
```
38-
You should see console output and a file at `./EFCore.Sqlite/bin/Debug/net8.0/artifacts/qwatch.ef.json`.
39-
4. **Gate with the CLI** (from repo root or here):
40-
```bash
41-
dotnet run --project ../tools/KeelMatrix.QueryWatch.Cli -- --input ./EFCore.Sqlite/bin/Debug/net8.0/artifacts/qwatch.ef.json --max-queries 50
42-
```
12+
## Start here
13+
Follow the **[Quick Start — Samples (local)](../README.md#quick-start--samples-local)** in the root README.
4314

44-
### Notes
45-
- These samples **compile only after** you add the `KeelMatrix.QueryWatch` and (for EF) `KeelMatrix.QueryWatch.EfCore` packages (Step 2).
46-
- If you get restore errors, confirm that `../artifacts/packages` exists and contains your `*.nupkg` files.
47-
- The EF Core sample uses a file-based SQLite DB under `./EFCore.Sqlite/app.db`. You can delete it safely.
15+
> After you run `dotnet pack ...` at the repo root, use `./init.ps1` (or `./init.sh`) once to add local packages. No other tweaks are needed.
4816
49-
### Dapper sample
50-
Run the Dapper sample:
17+
### Run a sample
5118
```bash
52-
dotnet run --project ./Dapper.Sqlite/Dapper.Sqlite.csproj
19+
dotnet run --project ./EFCore.Sqlite/EFCore.Sqlite.csproj -c Release
5320
```
21+
22+
For CLI usage examples, see `cli-examples.ps1` / `cli-examples.sh`.

src/KeelMatrix.QueryWatch.EfCore/KeelMatrix.QueryWatch.EfCore.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
<PackageId>KeelMatrix.QueryWatch.EfCore</PackageId>
1313
<Description>EF Core adapter for KeelMatrix.QueryWatch: wires a DbCommand interceptor and a UseQueryWatch(...) extension.</Description>
1414
<PackageTags>queries;performance;testing;efcore;interceptor;ci;gate</PackageTags>
15-
<RepositoryUrl>https://github.com/your-org/KeelMatrix.QueryWatch</RepositoryUrl>
16-
<PackageProjectUrl>https://github.com/your-org/KeelMatrix.QueryWatch#readme</PackageProjectUrl>
15+
<RepositoryUrl>https://github.com/KeelMatrix/QueryWatch</RepositoryUrl>
16+
<PackageProjectUrl>https://github.com/KeelMatrix/QueryWatch#readme</PackageProjectUrl>
1717
<PackageReadmeFile>README.md</PackageReadmeFile>
1818
<PackageLicenseExpression>MIT</PackageLicenseExpression>
1919
<PackageIcon>icon.png</PackageIcon>

0 commit comments

Comments
 (0)