QueryLens 1.0.0-preview.1

This is a prerelease version of QueryLens.
There is a newer version of this package available.
See the version list below for details.
dotnet add package QueryLens --version 1.0.0-preview.1
                    
NuGet\Install-Package QueryLens -Version 1.0.0-preview.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="QueryLens" Version="1.0.0-preview.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="QueryLens" Version="1.0.0-preview.1" />
                    
Directory.Packages.props
<PackageReference Include="QueryLens" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add QueryLens --version 1.0.0-preview.1
                    
#r "nuget: QueryLens, 1.0.0-preview.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package QueryLens@1.0.0-preview.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=QueryLens&version=1.0.0-preview.1&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=QueryLens&version=1.0.0-preview.1&prerelease
                    
Install as a Cake Tool

QueryLens

Validate your raw SQL at test time — not runtime.

QueryLens catches column typos, missing parameters, invalid functions, and dialect mistakes in your SQL before they hit production. Built for Dapper, ADO.NET, and any .NET code with hand-written SQL.

.NET 9 License: MIT


Why?

SQL queries in .NET are opaque strings. The compiler can't see them. A typo in a column name, a function that doesn't exist in your SQL Server version, a table that was renamed last week — you won't know until runtime. QueryLens fixes that.

Quick Start

dotnet add package QueryLens

1. Check for syntax errors

var query = new SqlQuery("SELECT * FROM customers WHERE created_date >= GETDATE()");

var result = SqlValidator.UseSqlServer().Validate(query);

Assert.True(result.IsValid);   // passes — valid T-SQL

That's it. One query, one validator, one assert.

2. Check for version-specific function errors

STRING_AGG was introduced in SQL Server 2017. If your production server runs 2014:

var query = new SqlQuery("SELECT STRING_AGG(name, ',') FROM departments");

var result = SqlValidator.UseSqlServer()
    .ServerVersion("2014")
    .AllowCustomFunctions(false)
    .Validate(query);

Assert.False(result.IsValid);
// QL0071: Function 'STRING_AGG' is not available in SQL Server version 2014.

3. Check for tables and columns that don't exist

var query = new SqlQuery("SELECT id, full_name, email FROM customers");

var result = SqlValidator.UseSqlServer()
    .WithSchema(s => s
        .Table("customers")
            .Column("id", SqlType.Int)
            .Column("name", SqlType.NVarChar)
            .Column("email", SqlType.NVarChar))
    .Validate(query);

Assert.False(result.IsValid);
// QL0011: Column 'full_name' does not exist in table 'customers'.

4. Check for missing parameters

var query = new SqlQuery("SELECT * FROM orders WHERE status = @Status AND id = @Id");

var result = SqlValidator.UseSqlServer()
    .Build()
    .Validate(query, new { Status = "active" });   // @Id is missing

Assert.False(result.IsValid);
// QL0030: SQL parameter '@Id' has no matching value in the provided parameters.

5. Catch identity column violations

var insert = new SqlInsert("INSERT INTO customers (id, name) VALUES (@Id, @Name)");

var result = SqlValidator.UseSqlServer()
    .WithSchema(s => s
        .Table("customers")
            .Column("id", SqlType.Int, isIdentity: true)
            .Column("name", SqlType.NVarChar))
    .Validate(insert);

Assert.False(result.IsValid);
// QL0060: Column 'id' is an identity column and cannot be explicitly set.

6. Warn on dangerous deletes

var delete = new SqlDelete("DELETE FROM customers");

var result = SqlValidator.UseSqlServer().Validate(delete);

Assert.Contains(result.Warnings, w => w.Code == "QL0040");
// QL0040: DELETE statement without WHERE clause.

Configure Once, Validate Everywhere

Set up your validator once at startup. Then every query validates itself:

// Call once — in an xUnit fixture, [ModuleInitializer], or test base class
QueryLensConfig.Configure(b =>
{
    b.UseSqlServer();
    b.WithSchema(s => s
        .Table("customers")
            .Column("id", SqlType.Int, isIdentity: true)
            .Column("name", SqlType.NVarChar)
            .Column("email", SqlType.NVarChar));
});

// Now every query validates itself
var query = new SqlQuery("SELECT id, name FROM customers");
Assert.True(query.IsValid);

var bad = new SqlQuery("SELECT id, phone FROM customers");
Assert.False(bad.IsValid);
// bad.ErrorSummary → "Column 'phone' does not exist in table 'customers'."

Works With Every Major SQL Dialect

SqlValidator.UseSqlServer()    // T-SQL: TOP, ISNULL, [brackets]
SqlValidator.UsePostgreSql()   // PG: LIMIT/OFFSET, COALESCE, "double quotes"
SqlValidator.UseMySql()        // MySQL: LIMIT, IFNULL, `backticks`
SqlValidator.UseSqlite()       // SQLite: LIMIT, lightweight functions
SqlValidator.UseOracle()       // Oracle: ROWNUM, NVL, DUAL

Each dialect ships with a complete JSON catalog of built-in functions (with version tags), commands, reserved words, and deprecated keywords.


Type System

QueryLens provides typed SQL wrappers. They implicitly convert to string, so they drop in wherever Dapper expects SQL:

// These just work with Dapper — no .Text or .ToString()
await connection.QueryAsync<Customer>(myQuery, new { Status = "active" });
await connection.ExecuteAsync(myInsert, new { Name = "Acme" });
Type For
SqlQuery SELECT
SqlInsert INSERT
SqlUpdate UPDATE
SqlDelete DELETE
SqlMerge MERGE / UPSERT
SqlStoredProc Stored procedures

Validation Rules

Every rule is independently toggleable. Start simple, enable more as your team is ready:

Rule Default What It Catches
ValidateSyntax ON Malformed SQL
ValidateTableExistence ON Table doesn't exist
ValidateColumnExistence ON Column doesn't exist
ValidateColumnMapping ON SELECT column doesn't map to C# model
ValidateParameterConsistency ON Missing or extra @Parameters
ValidateInsertColumnValueMatch ON INSERT column/value count mismatch
ValidateWhereClause ON UPDATE/DELETE without WHERE
ValidateIdentityColumns ON Writing to identity/computed columns
ValidateBuiltInFunctions ON Invalid or version-incompatible functions
ValidateRequiredColumns OFF Non-nullable columns missing from INSERT
ValidateJoinStructure OFF Invalid JOIN structure
ValidateAliasConsistency OFF Inconsistent alias usage
ValidateReservedWords OFF Reserved words as identifiers
ValidateDeprecatedSyntax OFF Deprecated syntax
var validator = SqlValidator.UseSqlServer()
    .Enable(Rules.ValidateRequiredColumns)
    .Disable(Rules.ValidateBuiltInFunctions)
    .Build();

Issue Codes

Code What It Means
QL0001 SQL syntax error
QL0010 Table doesn't exist
QL0011 Column doesn't exist
QL0020 SELECT column doesn't map to model property
QL0030 Missing parameter value
QL0031 Unused parameter
QL0040 UPDATE/DELETE without WHERE
QL0050 INSERT column/value count mismatch
QL0060 Writing to identity column
QL0061 Writing to computed column
QL0070 Unrecognized function
QL0071 Function not available in target version
QL0072 Too few function arguments
QL0073 Too many function arguments
QL0080 Required column missing from INSERT
QL0090 Table name is a reserved word
QL0091 Column name is a reserved word

Performance

Fast enough to validate your entire query catalog on every build:

Operation Time
Simple SELECT ~3 μs
Complex query (JOINs, GROUP BY) ~16 μs
100 mixed statements ~260 μs

What QueryLens Is Not

  • Not an ORM — it doesn't generate SQL or map results
  • Not a query optimizer — it doesn't suggest indexes
  • Not a migration tool — it doesn't apply schema changes
  • Not a runtime validator — all validation is static, at test time

License

MIT

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net9.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.3 1,033 4/12/2026
1.1.3-preview.40 72 5/3/2026
1.1.2 114 4/12/2026
1.1.1 120 4/12/2026
1.1.0 126 4/12/2026
1.0.0 145 4/11/2026
1.0.0-preview.10 84 4/7/2026
1.0.0-preview.9 71 4/5/2026
1.0.0-preview.8 85 4/5/2026
1.0.0-preview.7 66 4/5/2026
1.0.0-preview.6 89 4/5/2026
1.0.0-preview.4 77 4/4/2026
1.0.0-preview.3 94 4/4/2026
1.0.0-preview.1 82 4/2/2026