Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@
<RepositoryType>git</RepositoryType>
<PackageTags>sql;orm;aot;source-generator;database</PackageTags>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageIcon>logo-128.png</PackageIcon>
</PropertyGroup>
</Project>
7 changes: 6 additions & 1 deletion Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@
</Task>
</UsingTask>

<PropertyGroup>
<PackageReadmeSource Condition="'$(PackageReadmeSource)' == ''">$(MSBuildProjectDirectory)/README.md</PackageReadmeSource>
</PropertyGroup>

<Target Name="StripHtmlImages" BeforeTargets="_GetPackageFiles" Condition="'$(IsPackable)' == 'true'">
<StripImgTags InputFile="$(MSBuildThisFileDirectory)README.md"
<StripImgTags InputFile="$(PackageReadmeSource)"
OutputFile="$(IntermediateOutputPath)README.md" />
<ItemGroup>
<None Include="$(IntermediateOutputPath)README.md" Pack="true" PackagePath="\" />
<None Include="$(MSBuildThisFileDirectory)docs/images/logo-128.png" Pack="true" PackagePath="\" />
</ItemGroup>
</Target>
</Project>
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Type-safe SQL builder for .NET 10. Source generators + C# 12 interceptors emit a
| [`Quarry`](https://www.nuget.org/packages/Quarry) | [![Quarry](https://img.shields.io/nuget/v/Quarry.svg?maxAge=60)](https://www.nuget.org/packages/Quarry) | Runtime types: builders, schema DSL, dialects, executors. |
| [`Quarry.Generator`](https://www.nuget.org/packages/Quarry.Generator) | [![Quarry.Generator](https://img.shields.io/nuget/v/Quarry.Generator.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Generator) | Roslyn incremental source generator + interceptor emitter. |
| [`Quarry.Analyzers`](https://www.nuget.org/packages/Quarry.Analyzers) | [![Quarry.Analyzers](https://img.shields.io/nuget/v/Quarry.Analyzers.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Analyzers) | Compile-time SQL query analysis rules (QRA series) with code fixes. |
| [`Quarry.Analyzers.CodeFixes`](https://www.nuget.org/packages/Quarry.Analyzers.CodeFixes) | [![Quarry.Analyzers.CodeFixes](https://img.shields.io/nuget/v/Quarry.Analyzers.CodeFixes.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Analyzers.CodeFixes) | Code fix providers for QRA diagnostics. |
| [`Quarry.Tool`](https://www.nuget.org/packages/Quarry.Tool) | [![Quarry.Tool](https://img.shields.io/nuget/v/Quarry.Tool.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Tool) | CLI tool for migrations and database scaffolding (`quarry` command). |

---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<IsRoslynComponent>true</IsRoslynComponent>
<IsPackable>true</IsPackable>
<NoWarn>$(NoWarn);RS2008</NoWarn>
</PropertyGroup>

Expand Down
81 changes: 81 additions & 0 deletions src/Quarry.Analyzers.CodeFixes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# <img src="../../docs/images/logo-128.png" height="48"> Quarry

Type-safe SQL builder for .NET 10. Source generators + C# 12 interceptors emit all SQL at compile time. AOT compatible. Structured logging via Logsmith.

---

# Quarry.Analyzers.CodeFixes

Code fix providers for Quarry analyzer diagnostics. Adds IDE lightbulb actions that automatically rewrite flagged query patterns.

## Packages

| Name | NuGet | Description |
|------|-------|-------------|
| [`Quarry`](https://www.nuget.org/packages/Quarry) | [![Quarry](https://img.shields.io/nuget/v/Quarry.svg?maxAge=60)](https://www.nuget.org/packages/Quarry) | Runtime types: builders, schema DSL, dialects, executors. |
| [`Quarry.Generator`](https://www.nuget.org/packages/Quarry.Generator) | [![Quarry.Generator](https://img.shields.io/nuget/v/Quarry.Generator.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Generator) | Roslyn incremental source generator + interceptor emitter. |
| [`Quarry.Analyzers`](https://www.nuget.org/packages/Quarry.Analyzers) | [![Quarry.Analyzers](https://img.shields.io/nuget/v/Quarry.Analyzers.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Analyzers) | Compile-time SQL query analysis rules (QRA series) with code fixes. |
| [`Quarry.Analyzers.CodeFixes`](https://www.nuget.org/packages/Quarry.Analyzers.CodeFixes) | [![Quarry.Analyzers.CodeFixes](https://img.shields.io/nuget/v/Quarry.Analyzers.CodeFixes.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Analyzers.CodeFixes) | Code fix providers for QRA diagnostics. |
| [`Quarry.Tool`](https://www.nuget.org/packages/Quarry.Tool) | [![Quarry.Tool](https://img.shields.io/nuget/v/Quarry.Tool.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Tool) | CLI tool for migrations and database scaffolding (`quarry` command). |

---

## Installation

```xml
<PackageReference Include="Quarry.Analyzers.CodeFixes" Version="1.0.0"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
```

Requires `Quarry.Analyzers` to be referenced in the same project. The code fixes act on diagnostics reported by the analyzer package.

---

## Available Code Fixes

| Diagnostic | Fix Title | Transformation |
|------------|-----------|----------------|
| QRA101 | Replace Count() comparison with Any() | Rewrites `Count() > 0` to `Any()`, `Count() == 0` to `!Any()`. Handles async variants. |
| QRA102 | Replace single-value Contains with == | Rewrites `new[] { x }.Contains(col)` to `col == x`. |
| QRA201 | Remove unused join | Removes the `.Join(...)` call from the query chain, preserving the receiver. |

---

## Examples

### QRA101 — Count to Any

```csharp
// Before (flagged by QRA101)
var hasOrders = await db.Users
.Where(u => u.Orders.Count() > 0)
.ExecuteFetchAllAsync();

// After fix applied
var hasOrders = await db.Users
.Where(u => u.Orders.Any())
.ExecuteFetchAllAsync();
```

### QRA102 — Single-value IN to Equals

```csharp
// Before (flagged by QRA102)
db.Users.Where(u => new[] { 42 }.Contains(u.UserId));

// After fix applied
db.Users.Where(u => u.UserId == 42);
```

### QRA201 — Remove Unused Join

```csharp
// Before (flagged by QRA201)
db.Users.Join<Order>((u, o) => u.UserId == o.UserId.Id)
.Select((u, o) => u.UserName); // 'o' never used

// After fix applied
db.Users
.Select(u => u.UserName);
```
1 change: 1 addition & 0 deletions src/Quarry.Analyzers/Quarry.Analyzers.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<IsRoslynComponent>true</IsRoslynComponent>
<BuildOutputTargetFolder>analyzers/dotnet/cs</BuildOutputTargetFolder>
<IsPackable>true</IsPackable>
<NoWarn>$(NoWarn);RS2008</NoWarn>
</PropertyGroup>

Expand Down
126 changes: 126 additions & 0 deletions src/Quarry.Analyzers/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# <img src="../../docs/images/logo-128.png" height="48"> Quarry

Type-safe SQL builder for .NET 10. Source generators + C# 12 interceptors emit all SQL at compile time. AOT compatible. Structured logging via Logsmith.

---

# Quarry.Analyzers

Compile-time SQL query analysis rules for Quarry. 18 Roslyn diagnostics detect performance issues, wasteful patterns, and dialect-specific problems in Quarry query call sites.

## Packages

| Name | NuGet | Description |
|------|-------|-------------|
| [`Quarry`](https://www.nuget.org/packages/Quarry) | [![Quarry](https://img.shields.io/nuget/v/Quarry.svg?maxAge=60)](https://www.nuget.org/packages/Quarry) | Runtime types: builders, schema DSL, dialects, executors. |
| [`Quarry.Generator`](https://www.nuget.org/packages/Quarry.Generator) | [![Quarry.Generator](https://img.shields.io/nuget/v/Quarry.Generator.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Generator) | Roslyn incremental source generator + interceptor emitter. |
| [`Quarry.Analyzers`](https://www.nuget.org/packages/Quarry.Analyzers) | [![Quarry.Analyzers](https://img.shields.io/nuget/v/Quarry.Analyzers.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Analyzers) | Compile-time SQL query analysis rules (QRA series) with code fixes. |
| [`Quarry.Analyzers.CodeFixes`](https://www.nuget.org/packages/Quarry.Analyzers.CodeFixes) | [![Quarry.Analyzers.CodeFixes](https://img.shields.io/nuget/v/Quarry.Analyzers.CodeFixes.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Analyzers.CodeFixes) | Code fix providers for QRA diagnostics. |
| [`Quarry.Tool`](https://www.nuget.org/packages/Quarry.Tool) | [![Quarry.Tool](https://img.shields.io/nuget/v/Quarry.Tool.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Tool) | CLI tool for migrations and database scaffolding (`quarry` command). |

---

## Installation

```xml
<PackageReference Include="Quarry.Analyzers" Version="1.0.0"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
```

Requires `Quarry` and `Quarry.Generator` to be referenced in the same project.

---

## Diagnostic Rules

All rules are enabled by default. Suppress individual rules via `#pragma`, `.editorconfig`, or `[SuppressMessage]`.

### QRA1xx — Simplification

| ID | Title | Severity | What it detects |
|----|-------|----------|-----------------|
| QRA101 | Count compared to zero | Info | `Count() > 0`, `Count() == 0` — use `Any()` instead |
| QRA102 | Single-value IN clause | Info | `IN (@p0)` with one value — simplify to `==` |
| QRA103 | Tautological condition | Info | Always-true conditions (`1 = 1`, `col = col`) |
| QRA104 | Contradictory condition | Info | Always-false conditions (`x > 5 AND x < 3`) |
| QRA105 | Redundant condition | Info | Subsumed conditions (`x > 5 AND x > 3`) |
| QRA106 | Nullable without null check | Info | Nullable column in `==` comparison without null handling |

### QRA2xx — Wasted Work

| ID | Title | Severity | What it detects |
|----|-------|----------|-----------------|
| QRA201 | Unused join | Warning | Joined table not referenced in SELECT, WHERE, or ORDER BY |
| QRA202 | Wide table SELECT * | Info | `Select(u => u)` on tables exceeding column threshold |
| QRA203 | ORDER BY without LIMIT | Info | Sorting without pagination on unbounded result sets |
| QRA204 | Duplicate projection column | Info | Same column projected multiple times in SELECT |
| QRA205 | Cartesian product | Warning | JOIN with missing or trivial ON condition (`1 = 1`) |

### QRA3xx — Performance

| ID | Title | Severity | What it detects |
|----|-------|----------|-----------------|
| QRA301 | Leading wildcard LIKE | Info | `Contains()` → `LIKE '%…%'` prevents index usage |
| QRA302 | Function on column in WHERE | Info | `LOWER()`, `UPPER()`, `TRIM()`, etc. on columns in WHERE |
| QRA303 | OR across different columns | Info | `col1 = x OR col2 = y` prevents single-index scan |
| QRA304 | WHERE on non-indexed column | Info | Filter on column not covered by any declared index |

### QRA4xx — Patterns

| ID | Title | Severity | What it detects |
|----|-------|----------|-----------------|
| QRA401 | Query inside loop | Warning | Execution method inside `for`/`foreach`/`while`/LINQ — N+1 risk |
| QRA402 | Multiple queries on same table | Info | Multiple independent queries on the same entity in one method |

### QRA5xx — Dialect

| ID | Title | Severity | What it detects |
|----|-------|----------|-----------------|
| QRA501 | Dialect optimization available | Info | PostgreSQL: suggest `ILIKE` over `LOWER() + LIKE`; SQLite: suggest `COLLATE NOCASE` |
| QRA502 | Suboptimal for dialect | Warning | SQLite: `RIGHT JOIN` unsupported; SQL Server: `OFFSET` requires `ORDER BY` |

---

## Configuration

### EditorConfig

```ini
# .editorconfig
[*.cs]
# Column threshold for QRA202 (wide table SELECT *), default: 10
quarry_analyzers.wide_table_column_count = 12
```

### Suppressing Rules

```ini
# .editorconfig — suppress a rule project-wide
[*.cs]
dotnet_diagnostic.QRA203.severity = none
```

```csharp
// Per-site suppression
#pragma warning disable QRA301
var results = await db.Users
.Where(u => u.UserName.Contains(search))
.ExecuteFetchAllAsync();
#pragma warning restore QRA301
```

---

## Severity Summary

Four rules default to **Warning** — these indicate likely bugs or significant performance issues:

| ID | Rule |
|----|------|
| QRA201 | Unused join |
| QRA205 | Cartesian product |
| QRA401 | Query inside loop (N+1) |
| QRA502 | Suboptimal for dialect |

The remaining 14 rules default to **Info** — suggestions that may or may not apply depending on context.
1 change: 1 addition & 0 deletions src/Quarry.Generator/Quarry.Generator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<!-- Package metadata -->
<PackageId>Quarry.Generator</PackageId>
<Description>Source generators and analyzers for Quarry SQL builder</Description>
<IsPackable>true</IsPackable>
<DevelopmentDependency>true</DevelopmentDependency>
<IncludeBuildOutput>true</IncludeBuildOutput>
<BuildOutputTargetFolder>analyzers/dotnet/cs</BuildOutputTargetFolder>
Expand Down
15 changes: 15 additions & 0 deletions src/Quarry.Generator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# <img src="../../docs/images/logo-128.png" height="48"> Quarry

Type-safe SQL builder for .NET 10. Source generators + C# 12 interceptors emit all SQL at compile time. AOT compatible. Structured logging via Logsmith.

---

## Packages

| Name | NuGet | Description |
|------|-------|-------------|
| [`Quarry`](https://www.nuget.org/packages/Quarry) | [![Quarry](https://img.shields.io/nuget/v/Quarry.svg?maxAge=60)](https://www.nuget.org/packages/Quarry) | Runtime types: builders, schema DSL, dialects, executors. |
| [`Quarry.Generator`](https://www.nuget.org/packages/Quarry.Generator) | [![Quarry.Generator](https://img.shields.io/nuget/v/Quarry.Generator.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Generator) | Roslyn incremental source generator + interceptor emitter. |
| [`Quarry.Analyzers`](https://www.nuget.org/packages/Quarry.Analyzers) | [![Quarry.Analyzers](https://img.shields.io/nuget/v/Quarry.Analyzers.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Analyzers) | Compile-time SQL query analysis rules (QRA series) with code fixes. |
| [`Quarry.Analyzers.CodeFixes`](https://www.nuget.org/packages/Quarry.Analyzers.CodeFixes) | [![Quarry.Analyzers.CodeFixes](https://img.shields.io/nuget/v/Quarry.Analyzers.CodeFixes.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Analyzers.CodeFixes) | Code fix providers for QRA diagnostics. |
| [`Quarry.Tool`](https://www.nuget.org/packages/Quarry.Tool) | [![Quarry.Tool](https://img.shields.io/nuget/v/Quarry.Tool.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Tool) | CLI tool for migrations and database scaffolding (`quarry` command). |
7 changes: 7 additions & 0 deletions src/Quarry.Tool/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# <img src="../../docs/images/logo-128.png" height="48"> Quarry

Type-safe SQL builder for .NET 10. Source generators + C# 12 interceptors emit all SQL at compile time. AOT compatible. Structured logging via Logsmith.

---

# Quarry Migration Tool

Code-first migration scaffolding for Quarry. Reads your C# schema definitions via Roslyn, diffs them against the previous snapshot, and generates migration files — no database connection required.
Expand All @@ -9,6 +15,7 @@ Code-first migration scaffolding for Quarry. Reads your C# schema definitions vi
| [`Quarry`](https://www.nuget.org/packages/Quarry) | [![Quarry](https://img.shields.io/nuget/v/Quarry.svg?maxAge=60)](https://www.nuget.org/packages/Quarry) | Runtime types: builders, schema DSL, dialects, executors. |
| [`Quarry.Generator`](https://www.nuget.org/packages/Quarry.Generator) | [![Quarry.Generator](https://img.shields.io/nuget/v/Quarry.Generator.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Generator) | Roslyn incremental source generator + interceptor emitter. |
| [`Quarry.Analyzers`](https://www.nuget.org/packages/Quarry.Analyzers) | [![Quarry.Analyzers](https://img.shields.io/nuget/v/Quarry.Analyzers.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Analyzers) | Compile-time SQL query analysis rules (QRA series) with code fixes. |
| [`Quarry.Analyzers.CodeFixes`](https://www.nuget.org/packages/Quarry.Analyzers.CodeFixes) | [![Quarry.Analyzers.CodeFixes](https://img.shields.io/nuget/v/Quarry.Analyzers.CodeFixes.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Analyzers.CodeFixes) | Code fix providers for QRA diagnostics. |
| [`Quarry.Tool`](https://www.nuget.org/packages/Quarry.Tool) | [![Quarry.Tool](https://img.shields.io/nuget/v/Quarry.Tool.svg?maxAge=60)](https://www.nuget.org/packages/Quarry.Tool) | CLI tool for migrations and database scaffolding (`quarry` command). |

---
Expand Down
1 change: 1 addition & 0 deletions src/Quarry/Quarry.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<PackageId>Quarry</PackageId>
<Description>Type-safe SQL builder and query reader for .NET 10 with AOT support</Description>
<IsPackable>true</IsPackable>
<PackageReadmeSource>$(MSBuildThisFileDirectory)../../README.md</PackageReadmeSource>
</PropertyGroup>

<ItemGroup>
Expand Down
Loading