AutoQuery.Generator 1.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package AutoQuery.Generator --version 1.0.0
                    
NuGet\Install-Package AutoQuery.Generator -Version 1.0.0
                    
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="AutoQuery.Generator" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="AutoQuery.Generator" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="AutoQuery.Generator" />
                    
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 AutoQuery.Generator --version 1.0.0
                    
#r "nuget: AutoQuery.Generator, 1.0.0"
                    
#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 AutoQuery.Generator@1.0.0
                    
#: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=AutoQuery.Generator&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=AutoQuery.Generator&version=1.0.0
                    
Install as a Cake Tool

AutoQuery.Generator

NuGet NuGet Downloads CI License: MIT

๐Ÿ“– Documentation site ยท NuGet ยท Changelog

Compile-time query composition for IQueryable<T> via Roslyn incremental source generators.

Add [QuerySpec(typeof(Product))] to a partial query class and AutoQuery.Generator emits a strongly-typed Apply(IQueryable<Product>) method at build time. No reflection. No runtime scanning. AOT-friendly.

using AutoQuery;
using System.Linq;

[QuerySpec(typeof(Product))]
public partial class ProductQuery
{
    public string? Name { get; set; }
    public decimal? MinPrice { get; set; }
    public decimal? MaxPrice { get; set; }
    [QuerySort] public string? SortBy { get; set; }
    public bool SortDescending { get; set; }
    public int PageNumber { get; set; } = 1;
    public int PageSize { get; set; } = 20;
}

var filtered = new ProductQuery
{
    Name = "Laptop",
    MinPrice = 500,
    SortBy = "Name",
    PageNumber = 1,
    PageSize = 10,
}.Apply(products);

Installation

dotnet add package AutoQuery.Generator

Targets netstandard2.0 and works with modern SDK-style .NET projects.


Quick start

1. Define an entity and query spec

using AutoQuery;

public sealed class Product
{
    public string? Name { get; set; }
    public decimal Price { get; set; }
    public bool IsActive { get; set; }
}

[QuerySpec(typeof(Product))]
public partial class ProductQuery
{
    public string? Name { get; set; }
    public decimal? MinPrice { get; set; }
    public bool? IsActive { get; set; }
}

2. Use the generated Apply method

IQueryable<Product> query = dbContext.Products;
var spec = new ProductQuery { Name = "Phone", MinPrice = 100, IsActive = true };
var result = spec.Apply(query);

Generated output resembles:

public partial class ProductQuery
{
    public IQueryable<global::YourApp.Product> Apply(IQueryable<global::YourApp.Product> query)
    {
        if (Name is not null)
            query = query.Where(x => x.Name != null && x.Name.Contains(Name));
        if (MinPrice is not null)
            query = query.Where(x => x.Price >= MinPrice.Value);
        if (IsActive is not null)
            query = query.Where(x => x.IsActive == IsActive.Value);
        return query;
    }
}

Attributes

[QuerySpec(typeof(TEntity))]

Marks a partial class as a query spec for the target entity.

[QuerySpec(typeof(Order))]
public partial class OrderQuery { }

[QueryFilter("x => x.Category.Name == value")]

Overrides the default convention and uses your custom LINQ predicate expression. The token value is replaced with the query property access.

[QueryFilter("x => x.Category.Name == value")]
public string? CategoryName { get; set; }

[QueryIgnore]

Skips a property entirely.

[QueryIgnore]
public string? DebugOnly { get; set; }

[QuerySort]

Marks a string? property as the requested sort field.

[QuerySort]
public string? SortBy { get; set; }
public bool SortDescending { get; set; }

[QueryPage]

Marks pagination properties when you are not using the conventional names PageNumber and PageSize.

[QueryPage] public int ResultsPageNumber { get; set; } = 1;
[QueryPage] public int ResultsPageSize { get; set; } = 25;

Convention-based filters

Nullable properties become filters automatically unless excluded.

Spec property Generated predicate
string? Name x => x.Name != null && x.Name.Contains(Name)
bool? IsActive x => x.IsActive == IsActive.Value
int? CategoryId x => x.CategoryId == CategoryId.Value
decimal? MinPrice x => x.Price >= MinPrice.Value
decimal? MaxPrice x => x.Price <= MaxPrice.Value
DateTime? CreatedFrom x => x.Created >= CreatedFrom.Value
DateTime? CreatedTo x => x.Created <= CreatedTo.Value

Prefix/suffix conventions:

  • Min... โ†’ >=
  • Max... โ†’ <=
  • ...From โ†’ >=
  • ...To โ†’ <=

Sorting

When the spec contains a [QuerySort] string property and a bool property named SortDescending or IsDescending, AutoQuery emits switch-based sorting.

[QuerySpec(typeof(Product))]
public partial class ProductQuery
{
    public string? Name { get; set; }
    public decimal? Price { get; set; }
    [QuerySort] public string? SortBy { get; set; }
    public bool SortDescending { get; set; }
}

Generated shape:

if (SortBy is not null)
{
    query = (SortBy, SortDescending) switch
    {
        ("Name", false) => query.OrderBy(x => x.Name),
        ("Name", true)  => query.OrderByDescending(x => x.Name),
        ("Price", false) => query.OrderBy(x => x.Price),
        ("Price", true)  => query.OrderByDescending(x => x.Price),
        _ => query
    };
}

Pagination

When PageNumber and PageSize are present (or [QueryPage] annotated equivalents are detected), AutoQuery emits:

query = query.Skip((PageNumber - 1) * PageSize).Take(PageSize);

Example:

[QuerySpec(typeof(Product))]
public partial class ProductQuery
{
    public string? Name { get; set; }
    public int PageNumber { get; set; } = 1;
    public int PageSize { get; set; } = 20;
}

Diagnostics

Id Severity Description
AQ001 Error [QuerySpec] entity type could not be resolved.
AQ002 Error [QuerySpec] target class must be declared partial.
AQ003 Warning Spec has no filterable properties.

Comparison

Capability AutoQuery.Generator Manual LINQ Ardalis.Specification
Compile-time generated Apply method โœ… โŒ โŒ
Reflection-free โœ… โœ… Usually โœ…
Convention filters from DTO-like class โœ… โŒ โŒ
Custom inline filter expressions โœ… Manual only Via handwritten spec logic
Built-in sort switch generation โœ… Manual only Manual only
Built-in pagination generation โœ… Manual only Manual only
Runtime abstraction dependency None None Package dependency

License

MIT.

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

  • .NETStandard 2.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.0 101 7/10/2026
1.0.1 105 7/7/2026
1.0.0 113 6/25/2026