PepperX.QueryForge
1.0.6
dotnet add package PepperX.QueryForge --version 1.0.6
NuGet\Install-Package PepperX.QueryForge -Version 1.0.6
<PackageReference Include="PepperX.QueryForge" Version="1.0.6" />
<PackageVersion Include="PepperX.QueryForge" Version="1.0.6" />
<PackageReference Include="PepperX.QueryForge" />
paket add PepperX.QueryForge --version 1.0.6
#r "nuget: PepperX.QueryForge, 1.0.6"
#:package PepperX.QueryForge@1.0.6
#addin nuget:?package=PepperX.QueryForge&version=1.0.6
#tool nuget:?package=PepperX.QueryForge&version=1.0.6
![]()
PepperX.QueryForge
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
Queryagainst 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 logic —
AND/OR/AND NOT/OR NOTgroups, any depth. - 🌳 Grouping models — describes multi-level
key / count / itemshierarchies 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 | Versions 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. |
-
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.