PepperX.QueryForge 1.0.6

dotnet add package PepperX.QueryForge --version 1.0.6
                    
NuGet\Install-Package PepperX.QueryForge -Version 1.0.6
                    
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="1.0.6" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PepperX.QueryForge" Version="1.0.6" />
                    
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 1.0.6
                    
#r "nuget: PepperX.QueryForge, 1.0.6"
                    
#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@1.0.6
                    
#: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=1.0.6
                    
Install as a Cake Addin
#tool nuget:?package=PepperX.QueryForge&version=1.0.6
                    
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 has no execution logic. It doesn't run SQL. It just defines the models, a fluent builder, and a validation engine that every provider (Dapper today, EF Core and In-Memory next) builds on top of.

To actually run a Query against a database, install a provider — e.g. PepperX.QueryForge.Dapper. It's included automatically as a dependency.

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.

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 (1)

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

Package Downloads
PepperX.QueryForge.Dapper

High-performance execution provider for the PepperX.QueryForge core library. It translates abstract query models into optimized SQL and executes them against Microsoft SQL Server using Dapper, seamlessly handling hierarchical grouping, complex filtering, and Stored Procedure/TVF integration.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.6 103 7/11/2026
1.0.5 111 7/10/2026
1.0.4 106 7/10/2026
1.0.3 108 7/10/2026
1.0.1 105 7/10/2026
1.0.0 105 7/10/2026