QueryKit 0.1.0
See the version list below for details.
dotnet add package QueryKit --version 0.1.0
NuGet\Install-Package QueryKit -Version 0.1.0
<PackageReference Include="QueryKit" Version="0.1.0" />
<PackageVersion Include="QueryKit" Version="0.1.0" />
<PackageReference Include="QueryKit" />
paket add QueryKit --version 0.1.0
#r "nuget: QueryKit, 0.1.0"
#:package QueryKit@0.1.0
#addin nuget:?package=QueryKit&version=0.1.0
#tool nuget:?package=QueryKit&version=0.1.0
QueryKit 🎛️
QueryKit is a .NET library that makes it easier to query your data by providing a fluent and intuitive syntax for filtering and sorting. It's inspired by the Sieve library but with some differences.
Getting Started
dotnet add package QueryKit
If we wanted to apply a filter to a DbSet called People, we just have to do something like this:
var filterInput = """FirstName == "Jane" && Age > 10""";
var people = _dbContext.People
  	.ApplyQueryKitFilter(filterInput)
  	.ToList();
QueryKit will automatically translate this into an expression for you. You can even customize your property names:
var filterInput = """first == "Jane" && Age > 10""";
var config = new QueryKitConfiguration(config =>
{
    config.Property<Person>(x => x.FirstName).HasQueryName("first");
});
var people = _dbContext.People
  	.ApplyQueryKitFilter(filterInput, config)
  	.ToList();
Sorting works too:
var filterInput = """first == "Jane" && Age > 10""";
var config = new QueryKitConfiguration(config =>
{
    config.Property<Person>(x => x.FirstName).HasQueryName("first");
});
var people = _dbContext.People
  	.ApplyQueryKitFilter(filterInput, config)
  	.ApplyQueryKitSort("first, Age desc", config)
  	.ToList();
And that's the basics! There's no services to inject or global set up to worry about, just apply what you want and call it a day. For a full list of capables, see below.
Filtering
Usage
To apply filters to your queryable, you just need to pass an input string with your filtering input to ApplyQueryKitFilter off of a queryable:
var people = _dbContext.People.ApplyQueryKitFilter("Age < 10").ToList();
You can also pass a configuration like this. More on configuration options below.
var config = new QueryKitConfiguration(config =>
{
    config.Property<SpecialPerson>(x => x.FirstName)
     	 		.HasQueryName("first")
      		.PreventSort();
});
var people = _dbContext.People
  		.ApplyQueryKitFilter("first == "Jane" && Age < 10", config)
  		.ToList();
Logical Operators
When filtering, you can use logical operators && for and as well as || for or. For example:
var input = """FirstName == "Jane" && Age < 10""";
var input = """FirstName == "Jane" || FirstName == "John" """;
Additionally, you can use ^^ for an in operator. You can add an * and use ^^* for case-insensitivity as well:
var input = """(Age ^^ [20, 30, 40]) && (BirthMonth ^^* ["January", "February", "March"]) || (Id ^^ ["6d623e92-d2cf-4496-a2df-f49fa77328ee"])""";
Order of Operations
You can use order of operation with parentheses like this:
var input = """(FirstName == "Jane" && Age < 10) || FirstName == "John" """;
Comparison Operators
There's a wide variety of comparison operators that use the same base syntax as Sieve's operators. To do a case-insensitive operation, just append a  * at the end of the operator.
| Name | Operator | Case Insensitive Operator | 
|---|---|---|
| Equals | == | ==* | 
| Not Equals | != | != | 
| Greater Than | > | N/A | 
| Less Than | < | N/A | 
| Greater Than Or Equal | >= | N/A | 
| Less Than Or Equal | ⇐ | N/A | 
| Starts With | _= | _=* | 
| Does Not Start With | !_= | !_=* | 
| Ends With | _-= | _-=* | 
| Does Not End With | !_-= | !_-=* | 
| Contains | @= | @=* | 
| Does Not Contain | !@= | !@=* | 
Filtering Notes
- stringand- guidproperties should be wrapped in double quotes- nulldoesn't need quotes:- var input = "Title == null";
- Double quotes can be escaped by using a similar syntax to raw-string literals introduced in C#11: - var input = """""Title == """lamb is great on a "gee-ro" not a "gy-ro" sandwich""" """""; // OR var input = """""""""Title == """"lamb is great on a "gee-ro" not a "gy-ro" sandwich"""" """"""""";
 
- Dates and times use ISO format: - DateOnly:- var filterInput = "Birthday == 2022-07-01";
- DateTimeOffset:- var filterInput = "Birthday == 2022-07-01T00:00:03Z";
 
- DateTime:- var filterInput = "Birthday == 2022-07-01";- var filterInput = "Birthday == 2022-07-01T00:00:03";
- var filterInput = "Birthday == 2022-07-01T00:00:03+01:00";
 
- TimeOnly:- var filterInput = "Time == 12:30:00";
 
- boolproperties need to use- == true,- == false, or the same using the- !=operator. they can not be standalone properies:- ❌ var input = """Title == "chicken & waffles" && Favorite""";
- ✅ var input = """Title == "chicken & waffles" && Favorite == true""";
 
- ❌ 
Complex Example
var input = """(Title == "lamb" && ((Age >= 25 && Rating < 4.5) || (SpecificDate <= 2022-07-01T00:00:03Z && Time == 00:00:03)) && (Favorite == true || Email.Value _= "hello@gmail.com"))""";
Property Settings
Filtering is set up to create an expression using the property names you have on your entity, but you can pass in a config to customize things a bit when needed.
- HasQueryName()to create a custom alias for a property. For exmaple, we can make- FirstNamealiased to- first.
- PreventFilter()to prevent filtering on a given property
var input = $"""first == "Jane" || Age > 10""";
var config = new QueryKitConfiguration(config =>
{
    config.Property<SpecialPerson>(x => x.FirstName)
     	 		.HasQueryName("first");
    config.Property<SpecialPerson>(x => x.Age)
      		.PreventFilter();
});
Nested Objects
Say we have a nested object like this:
public class SpecialPerson
{
    public Guid Id { get; set; } = Guid.NewGuid();
    public EmailAddress Email { get; set; }
}
public class EmailAddress : ValueObject
{
    public EmailAddress(string? value)
    {
        Value = value;
    }
    
    public string? Value { get; private set; }
}
It might have an EF Config like this:
public sealed class PersonConfiguration : IEntityTypeConfiguration<SpecialPerson>
{
    public void Configure(EntityTypeBuilder<SpecialPerson> builder)
    {
        builder.HasKey(x => x.Id);
        
      // Option 1
        builder.Property(x => x.Email)
            .HasConversion(x => x.Value, x => new EmailAddress(x))
            .HasColumnName("email");      
      
        // Option 2      
        builder.OwnsOne(x => x.Email, opts =>
        {
            opts.Property(x => x.Value).HasColumnName("email");
        }).Navigation(x => x.Email)
            .IsRequired();
    }
}
Warning EF properties configured with
HasConversionare not supported at this time -- if this is a blocker for you, i'd love to hear your use case
To actually use the nested properties, you can do something like this:
var input = $"""Email.Value == "{value}" """;
// or with an alias...
var input = $"""email == "hello@gmail.com" """;
var config = new QueryKitConfiguration(config =>
{
    config.Property<SpecialPerson>(x => x.Email.Value).HasQueryName("email");
});
Sorting
Sorting is a more simplistic flow. It's just an input with a comma delimited list of properties to sort by.
Rules
- use ascordescto designate if you want it to be ascending or descending. If neither is used, QueryKit will assumeasc
- You can use Sieve syntax as well by prefixing a property with -to designate it asdesc
- Spaces after commas are optional
So all of these are valid:
var input = "Title";
var input = "Title, Age desc";
var input = "Title desc, Age desc";
var input = "Title, Age";
var input = "Title asc, -Age";
var input = "Title, -Age";
Property Settings
Sorting is set up to create an expression using the property names you have on your entity, but you can pass in a config to customize things a bit when needed.
- Just as with filtering, HasQueryName()to create a custom alias for a property. For exmaple, we can makeFirstNamealiased tofirst.
- PreventSort()to prevent filtering on a given property
var input = $"""Age desc, first"";
var config = new QueryKitConfiguration(config =>
{
    config.Property<SpecialPerson>(x => x.FirstName)
     	 		.HasQueryName("first")
      		.PreventSort();
});
| Product | Versions Compatible and additional computed target framework versions. | 
|---|---|
| .NET | net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. 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. | 
- 
                                                    net7.0- Ardalis.SmartEnum (>= 7.0.0)
- Sprache (>= 2.3.1)
 
NuGet packages (1)
Showing the top 1 NuGet packages that depend on QueryKit:
| Package | Downloads | 
|---|---|
| KayordKit KayordKit to guide the way | 
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | 
|---|---|---|
| 1.9.8 | 112 | 10/29/2025 | 
| 1.9.7 | 1,033 | 9/28/2025 | 
| 1.9.6 | 166 | 9/28/2025 | 
| 1.9.5 | 177 | 9/28/2025 | 
| 1.9.4 | 769 | 9/5/2025 | 
| 1.9.3 | 182 | 9/5/2025 | 
| 1.9.2 | 6,864 | 7/1/2025 | 
| 1.9.1.1 | 186 | 7/1/2025 | 
| 1.9.0 | 189 | 7/1/2025 | 
| 1.8.1 | 219 | 6/28/2025 | 
| 1.8.0 | 1,101 | 6/25/2025 | 
| 1.7.0 | 183 | 6/24/2025 | 
| 1.6.0 | 201 | 6/23/2025 | 
| 1.5.0 | 37,910 | 12/5/2024 | 
| 1.4.4 | 13,486 | 11/2/2024 | 
| 1.4.3 | 3,678 | 9/7/2024 | 
| 1.4.2 | 2,436 | 8/14/2024 | 
| 1.4.1 | 3,154 | 7/19/2024 | 
| 1.4.0 | 9,170 | 6/23/2024 | 
| 1.3.3 | 5,416 | 4/16/2024 | 
| 1.3.2 | 892 | 4/12/2024 | 
| 1.3.1 | 343 | 4/12/2024 | 
| 1.3.0 | 2,042 | 3/24/2024 | 
| 1.2.1 | 11,825 | 1/20/2024 | 
| 1.2.0 | 549 | 1/16/2024 | 
| 1.1.0 | 18,579 | 12/22/2023 | 
| 1.0.0 | 548 | 11/15/2023 | 
| 0.6.1 | 1,556 | 9/8/2023 | 
| 0.6.0 | 796 | 7/24/2023 | 
| 0.5.0-pre002 | 267 | 7/19/2023 | 
| 0.5.0-pre001 | 195 | 7/19/2023 | 
| 0.4.0 | 291 | 7/11/2023 | 
| 0.3.0 | 240 | 6/2/2023 | 
| 0.2.0 | 273 | 5/1/2023 | 
| 0.1.1 | 250 | 5/1/2023 | 
| 0.1.0 | 330 | 4/29/2023 |