PepperX.QueryForge 2.1.0

dotnet add package PepperX.QueryForge --version 2.1.0
                    
NuGet\Install-Package PepperX.QueryForge -Version 2.1.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="PepperX.QueryForge" Version="2.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PepperX.QueryForge" Version="2.1.0" />
                    
Directory.Packages.props
<PackageReference Include="PepperX.QueryForge" />
                    
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 PepperX.QueryForge --version 2.1.0
                    
#r "nuget: PepperX.QueryForge, 2.1.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 PepperX.QueryForge@2.1.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=PepperX.QueryForge&version=2.1.0
                    
Install as a Cake Addin
#tool nuget:?package=PepperX.QueryForge&version=2.1.0
                    
Install as a Cake Tool

Part of PepperX Ecosystem

PepperX.QueryForge Logo

PepperX.QueryForge

NuGet Version .NET License

What this is

PepperX.QueryForge is the abstract core of the QueryForge ecosystem: the shared vocabulary for describing "filter this, sort it like that, page it, maybe group it" — as a plain C# object or a plain JSON payload — without tying that intent to any particular database or library.

It defines the models, a fluent builder, and a validation engine that every provider builds on top of. It runs no SQL and has no dependencies.

It does, however, ship one execution engine — the in-memory one, since running a Query over an IEnumerable<T> needs nothing external:

var result = products.ToQueryResult(query);   // same QueryResult<T> every provider returns

To run a Query against a database, add a provider: PepperX.QueryForge.Dapper for parameterized SQL over Dapper (SQL Server, PostgreSQL, MySQL/MariaDB, Oracle, SQLite), or PepperX.QueryForge.EFCore to have Entity Framework Core generate the SQL from your model.

At a glance

  • 🧱 One shape, Query — filters, sorting, paging, and grouping, whether it comes from C# or from a client as JSON.
  • 🔍 Nested filter logicAND / OR / AND NOT / OR NOT groups, any depth.
  • 🌳 Grouping models — describes multi-level key / count / items hierarchies for providers to build.
  • 🛡️ Validation engine — silently strip or hard-block invalid columns/paging, shared by every provider.
  • 🔌 Provider-agnostic — write the intent once, plug in whichever execution engine you need.

Install

dotnet add package PepperX.QueryForge

(You'll rarely install this directly — it comes along with whichever provider you pick.)

The Query object

public class Query
{
    public QueryCriteria Criteria { get; set; }                       // filters
    public QueryPaging Paging { get; set; }                           // { Size, Number }
    public IReadOnlyList<string> SelectColumns { get; set; }          // projection
    public IReadOnlyList<SortDescriptor> SortColumns { get; set; }    // ORDER BY
    public IReadOnlyList<GroupByDescriptor> GroupByColumns { get; set; } // GROUP BY / hierarchy
}

Build one by hand, deserialize it straight from a client's JSON body, or use the fluent builder:

var query = QueryBuilder.New()
    .Select("Id", "Name", "Country")
    .Sort(new SortDescriptor("Name"))
    .Page(size: 20, number: 1)
    .Build();

Filtering

Criteria is a tree: groups of conditions, joined by a Logic, where each group is itself joined to the others by a Logic.

var criteria = new QueryCriteria(
    logic: Logic.And,
    groups:
    [
        new ConditionGroup(
            logic: Logic.Or,
            conditions:
            [
                new Condition("Country", ConditionOperator.Equals, "USA"),
                new Condition("Country", ConditionOperator.Equals, "Germany")
            ])
    ]);

var query = QueryBuilder.Where(criteria).Build();

Equivalent JSON from a client:

{
  "criteria": {
    "logic": 0,                  // Logic.And -> combine the groups below with AND (only one group here)
    "groups": [
      {
        "logic": 1,              // Logic.Or  -> Country = 'USA' OR Country = 'Germany'
        "conditions": [
          { "columnName": "Country", "operator": 0, "value": "USA" },      // operator 0 = Equals
          { "columnName": "Country", "operator": 0, "value": "Germany" }   // operator 0 = Equals
        ]
      }
    ]
  }
}

Logic: 0=And, 1=Or, 2=AndNot, 3=OrNot

ConditionOperator covers the usual set: Equals, NotEquals, Contains, NotContains, StartsWith, EndsWith, LessThan, GreaterThan, LessThanOrEqualTo, GreaterThanOrEqualTo, Between.

Grouping

Add GroupByColumns and a provider turns a flat result into a nested tree instead — this library just defines that shape (HierarchyNode<T>: Key, Count, SubGroups, Items), a provider does the actual grouping:

var query = QueryBuilder.New()
    .GroupBy(new GroupByDescriptor("Country"), new GroupByDescriptor("Department"))
    .Page(5, 1) // paginates the top-level groups
    .Build();

Validation

Never trust a Query that came from outside your API. Validate() supports two modes:

Mode Behavior
SilentStrip Quietly removes denied/disallowed columns and clamps paging — the request still succeeds.
ThrowException Throws a QueryValidationException listing every violated rule.
query.Validate(rules =>
{
    rules.Select(c => c.Deny("PasswordHash", "SecretKey"));
    rules.PageSize(p => p.Max(100));
}, QueryValidationMode.SilentStrip);

The result contract

Every provider returns the same QueryResult<TModel>, whichever mode you used:

public record QueryResult<TModel>
{
    public QueryResultMeta Meta { get; init; }                     // { Total: { Rows, Pages }, Type }
    public IReadOnlyList<TModel> Models { get; init; }             // populated when Type == Flat
    public IReadOnlyList<HierarchyNode<TModel>> Groups { get; init; } // populated when Type == Grouped
}

Providers built on this core

Provider Package Status
Dapper (SQL Server) PepperX.QueryForge.Dapper ✅ Released
Entity Framework Core PepperX.QueryForge.EFCore 🔧 In Development
In-Memory PepperX.QueryForge.InMemory 📋 Planned

🤝 Contributing & License

This project is part of the PepperX Ecosystem. Licensed under the MIT License — see the LICENSE file for details.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  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.
  • net10.0

    • No dependencies.

NuGet packages (3)

Showing the top 3 NuGet packages that depend on PepperX.QueryForge:

Package Downloads
PepperX.QueryForge.Dapper

High-performance execution provider for the PepperX.QueryForge core library. It compiles abstract query models into parameterized SQL and executes them with Dapper against SQL Server, PostgreSQL, MySQL/MariaDB and Oracle, handling hierarchical grouping, complex filtering, and function/procedure integration. No schema permissions or deployed database objects required.

PepperX.QueryForge.InMemory

In-memory execution provider for PepperX.QueryForge. Runs the same dynamic filtering, sorting, paging and hierarchical grouping against any IEnumerable or IQueryable — no database, no dependencies. Ideal for cached collections, API composition, unit tests, and as the reference implementation the database providers are asserted against.

PepperX.QueryForge.EFCore

Entity Framework Core execution provider for PepperX.QueryForge. Translates abstract query models into expression trees so EF Core generates the SQL, which means dynamic filtering, sorting, paging and hierarchical grouping work on every database EF Core supports and respect your entity model, global query filters and value converters.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.1.0 130 8/3/2026
2.0.0 133 8/1/2026
1.0.7 119 7/24/2026
1.0.6 118 7/11/2026
1.0.5 121 7/10/2026
1.0.4 118 7/10/2026
1.0.3 119 7/10/2026
1.0.1 118 7/10/2026
1.0.0 116 7/10/2026