Follow-up to PR #22 — replaces the per-dialect Adapter nested classes (the residual duplication after #22's first cut) with a shared IQueryBreakdownCollectionView interface implemented directly on each dialect's QueryBreakdownCollection.
What's new in the foundation
Strata.SqlTools.Breakdowns.SqlServer:
IQueryBreakdownCollectionView — dialect-neutral view exposing QueryCount, UniqueParameterCount, TotalSelectedColumns, UniqueTableCount, QueriesForReport (typed against the SqlServer QueryBreakdown base; PG/Snowflake satisfy via IReadOnlyList<T> covariance), and ParameterUsageRecords.
ParameterUsageRecord — record type for per-parameter usage stats, projected from each dialect's ParameterUsageReport.
What's gone from the Markdown layer
Markdown.Common.ICollectionMarkdownData — replaced by IQueryBreakdownCollectionView.
Markdown.Common.ParameterUsageRow — replaced by ParameterUsageRecord (same shape, foundation-level).
The 3 Adapter nested classes in the dialect wrappers — collections now implement the view directly.
What stayed the same
All three dialect-specific ParameterUsageReport classes (their ToString() overrides genuinely differ; unifying is a separate API conversation).
All three public QueryBreakdownCollectionGenerator classes — same method signatures, just slimmer bodies (no Adapter, collection is passed straight through).
Snowflake wrapper migrated to the same pattern while preserving its GenerateSnowflakeFeaturesAnalysis and feature-aware QueryCompositionReport callback.
Public API delta
Added: SqlServer.IQueryBreakdownCollectionView, SqlServer.ParameterUsageRecord. Each dialect's QueryBreakdownCollection now also implements the interface explicitly (members aren't visible on the concrete type without casting — no source-compat issue).
duplicated_blocks measure drops from current 4 (which were also the residual from PR #22 since the new commits haven't been scanned yet) to 0
## Summary
Follow-up to PR #22 — replaces the per-dialect `Adapter` nested classes (the residual duplication after #22's first cut) with a shared `IQueryBreakdownCollectionView` interface implemented directly on each dialect's `QueryBreakdownCollection`.
## What's new in the foundation
`Strata.SqlTools.Breakdowns.SqlServer`:
- **`IQueryBreakdownCollectionView`** — dialect-neutral view exposing `QueryCount`, `UniqueParameterCount`, `TotalSelectedColumns`, `UniqueTableCount`, `QueriesForReport` (typed against the SqlServer `QueryBreakdown` base; PG/Snowflake satisfy via `IReadOnlyList<T>` covariance), and `ParameterUsageRecords`.
- **`ParameterUsageRecord`** — record type for per-parameter usage stats, projected from each dialect's `ParameterUsageReport`.
## What's gone from the Markdown layer
- `Markdown.Common.ICollectionMarkdownData` — replaced by `IQueryBreakdownCollectionView`.
- `Markdown.Common.ParameterUsageRow` — replaced by `ParameterUsageRecord` (same shape, foundation-level).
- The 3 `Adapter` nested classes in the dialect wrappers — collections now implement the view directly.
## What stayed the same
- All three dialect-specific `ParameterUsageReport` classes (their `ToString()` overrides genuinely differ; unifying is a separate API conversation).
- All three public `QueryBreakdownCollectionGenerator` classes — same method signatures, just slimmer bodies (no `Adapter`, collection is passed straight through).
- Snowflake wrapper migrated to the same pattern while preserving its `GenerateSnowflakeFeaturesAnalysis` and feature-aware `QueryCompositionReport` callback.
## Public API delta
- **Added**: `SqlServer.IQueryBreakdownCollectionView`, `SqlServer.ParameterUsageRecord`. Each dialect's `QueryBreakdownCollection` now also implements the interface explicitly (members aren't visible on the concrete type without casting — no source-compat issue).
- **Removed**: none.
## Test plan
- [x] `dotnet build -c Release` — 0 errors
- [x] `dotnet test ... -c Release --no-build` — 1180 passed, 0 failed
- [ ] Gitea Actions scans this PR
- [ ] `duplicated_blocks` measure drops from current 4 (which were also the residual from PR #22 since the new commits haven't been scanned yet) to 0
Replaces the per-dialect <c>Adapter</c> nested classes (which were
themselves the leftover duplication after PR #22's first cut) with a
shared <c>IQueryBreakdownCollectionView</c> interface implemented
directly on each dialect's <c>QueryBreakdownCollection</c>.
New foundation types in <c>Strata.SqlTools.Breakdowns.SqlServer</c>:
- **<c>IQueryBreakdownCollectionView</c>** — dialect-neutral view
exposing QueryCount, UniqueParameterCount, TotalSelectedColumns,
UniqueTableCount, QueriesForReport (typed against the SqlServer
<c>QueryBreakdown</c> base — PG/Snowflake satisfy via <c>IReadOnlyList</c>
covariance), and ParameterUsageRecords.
- **<c>ParameterUsageRecord</c>** — record type for per-parameter usage
stats, projected from each dialect's <c>ParameterUsageReport</c>.
The three dialect <c>QueryBreakdownCollection</c> classes now implement
the interface explicitly — a handful of one-line forwarders per class.
The Markdown layer's old <c>ICollectionMarkdownData</c> interface and
the writer-internal <c>ParameterUsageRow</c> type are deleted; the
template and writer take <c>IQueryBreakdownCollectionView</c> and
<c>ParameterUsageRecord</c> directly.
Net effect on the Markdown wrappers:
- <c>Markdown.SqlServer.QueryBreakdownCollectionGenerator</c> loses
its <c>Adapter</c> nested class and its 6 forwarders pass <c>collection</c>
straight through.
- <c>Markdown.PostgreSql.QueryBreakdownCollectionGenerator</c> ditto.
- <c>Markdown.Snowflake.QueryBreakdownCollectionGenerator</c> migrated
to the same pattern; its dialect-specific
<c>GenerateSnowflakeFeaturesAnalysis</c> and feature-aware
<c>QueryCompositionReport</c> callback stay intact (they still call
<c>CollectionReportWriter</c> directly).
Public API additions: <c>IQueryBreakdownCollectionView</c> and
<c>ParameterUsageRecord</c> (both new, both opt-in). Public API
removals: none — the dialect <c>ParameterUsageReport</c> classes are
untouched and the dialect <c>QueryBreakdownCollectionGenerator</c>
public surface is identical.
All 1180 tests stay green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Follow-up to PR #22 — replaces the per-dialect
Adapternested classes (the residual duplication after #22's first cut) with a sharedIQueryBreakdownCollectionViewinterface implemented directly on each dialect'sQueryBreakdownCollection.What's new in the foundation
Strata.SqlTools.Breakdowns.SqlServer:IQueryBreakdownCollectionView— dialect-neutral view exposingQueryCount,UniqueParameterCount,TotalSelectedColumns,UniqueTableCount,QueriesForReport(typed against the SqlServerQueryBreakdownbase; PG/Snowflake satisfy viaIReadOnlyList<T>covariance), andParameterUsageRecords.ParameterUsageRecord— record type for per-parameter usage stats, projected from each dialect'sParameterUsageReport.What's gone from the Markdown layer
Markdown.Common.ICollectionMarkdownData— replaced byIQueryBreakdownCollectionView.Markdown.Common.ParameterUsageRow— replaced byParameterUsageRecord(same shape, foundation-level).Adapternested classes in the dialect wrappers — collections now implement the view directly.What stayed the same
ParameterUsageReportclasses (theirToString()overrides genuinely differ; unifying is a separate API conversation).QueryBreakdownCollectionGeneratorclasses — same method signatures, just slimmer bodies (noAdapter, collection is passed straight through).GenerateSnowflakeFeaturesAnalysisand feature-awareQueryCompositionReportcallback.Public API delta
SqlServer.IQueryBreakdownCollectionView,SqlServer.ParameterUsageRecord. Each dialect'sQueryBreakdownCollectionnow also implements the interface explicitly (members aren't visible on the concrete type without casting — no source-compat issue).Test plan
dotnet build -c Release— 0 errorsdotnet test ... -c Release --no-build— 1180 passed, 0 failedduplicated_blocksmeasure drops from current 4 (which were also the residual from PR #22 since the new commits haven't been scanned yet) to 0