### QueryKit Sorting Examples (C#) Source: https://github.com/pdevito3/querykit/blob/main/README.md This C# snippet provides examples of valid input strings for sorting using QueryKit. It demonstrates various syntaxes for specifying ascending (`asc`) and descending (`desc`) order, including the Sieve syntax (`-`) and optional spaces after commas. ```csharp 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"; ``` -------------------------------- ### Handle QueryKit Exceptions in C# Source: https://context7.com/pdevito3/querykit/llms.txt This example illustrates comprehensive error handling for various QueryKit parsing and validation exceptions. It relies on the QueryKit library and its exception namespaces, with specific catches for syntax, property, and configuration errors. Inputs are invalid query strings or misconfigured contexts, outputting error messages for user feedback; limitations include needing to handle multiple exception types and ensuring proper DbContext setup for features like SoundsLike. ```csharp using QueryKit; using QueryKit.Exceptions; public class Person { public string Name { get; set; } public int Age { get; set; } } try { // Invalid syntax - missing quotes around string var invalidSyntax = "Name == John"; var result = dbContext.People.ApplyQueryKitFilter(invalidSyntax).ToList(); } catch (ParsingException ex) { // Thrown for invalid syntax or operators Console.WriteLine($"Parsing error: {ex.Message}"); // Return HTTP 400 Bad Request } try { // Unknown property name var unknownProperty = """InvalidProperty == \"test\" """; var result = dbContext.People.ApplyQueryKitFilter(unknownProperty).ToList(); } catch (UnknownFilterPropertyException ex) { // Thrown when property is not found Console.WriteLine($"Unknown property: {ex.Message}"); // Return HTTP 400 Bad Request } try { // Invalid sort property var invalidSort = "InvalidProperty asc"; var result = dbContext.People.ApplyQueryKitSort(invalidSort).ToList(); } catch (SortParsingException ex) { // Thrown for sort parsing errors Console.WriteLine($"Sort error: {ex.Message}"); // Return HTTP 400 Bad Request } try { // Using SoundsLike without DbContext configuration var soundsLike = """Name ~~ \"Jon\" """; var result = dbContext.People.ApplyQueryKitFilter(soundsLike).ToList(); } catch (QueryKitDbContextTypeException ex) { // Thrown when DbContext type is required but not provided Console.WriteLine($"DbContext error: {ex.Message}"); } catch (SoundsLikeNotImplementedException ex) { // Thrown when soundex is not configured Console.WriteLine($"Soundex not configured: {ex.Message}"); } try { // Generic parsing errors var result = dbContext.People.ApplyQueryKitFilter("malformed input").ToList(); } catch (QueryKitParsingException ex) { // General parsing exception base class Console.WriteLine($"Parsing error: {ex.Message}"); } catch (QueryKitException ex) { // Base exception for all QueryKit errors Console.WriteLine($"QueryKit error: {ex.Message}"); } // Practical API error handling public IActionResult GetPeople([FromQuery] string filter, [FromQuery] string sort) { try { var people = _dbContext.People .ApplyQueryKitFilter(filter) .ApplyQueryKitSort(sort) .ToList(); return Ok(people); } catch (QueryKitException ex) { return BadRequest(new { error = ex.Message }); } } ``` -------------------------------- ### Parameter Type Conversion Examples in C# Source: https://github.com/pdevito3/querykit/blob/main/README.md Demonstrates how QueryKit automatically handles type conversions for parameters used in custom operations, including booleans, numeric types, dates, and strings. ```csharp // Boolean parameters var input = """isEligible == true"""; // Converts "true" to bool // Numeric parameters var input = """totalScore > 85.5"""; // Converts "85.5" to decimal/double var input = """itemCount >= 10"""; // Converts "10" to int // Date parameters var input = """lastLoginAfter == \"2023-12-01T00:00:00Z\" """; // Converts to DateTime // String parameters (with quotes) var input = """categoryMatches == \"electronics\" """; // Keeps as string ``` -------------------------------- ### Configure custom property names Source: https://github.com/pdevito3/querykit/blob/main/README.md Customizes property names for filters using QueryKitConfiguration. The example maps 'FirstName' to 'first'. ```csharp var filterInput = """first == \"Jane\" && Age > 10"""; var config = new QueryKitConfiguration(config => { config.Property(x => x.FirstName).HasQueryName("first"); }); var people = _dbContext.People .ApplyQueryKitFilter(filterInput, config) .ToList(); ``` -------------------------------- ### Apply Aggregate QueryKit Filters and Sorting (C#) Source: https://github.com/pdevito3/querykit/blob/main/README.md Combine filtering and sorting in a single operation using QueryKit. This example demonstrates how to apply both `Filters` and `SortOrder` from `QueryKitData` along with a custom `Configuration` to a `DbContext`. ```csharp var config = new QueryKitConfiguration(config => { config.Property(x => x.FirstName).HasQueryName("first"); }); var people = _dbContext.People .ApplyQueryKit(new QueryKitData() { Filters = """first == \"Jane\" && Age > 10""", SortOrder = "first, Age desc", Configuration = config }) .ToList(); ``` -------------------------------- ### Apply basic filter to DbSet Source: https://github.com/pdevito3/querykit/blob/main/README.md Applies a filter to a DbSet using QueryKit. This example filters a People collection by FirstName and Age. ```csharp var filterInput = """FirstName == \"Jane\" && Age > 10"""; var people = _dbContext.People .ApplyQueryKitFilter(filterInput) .ToList(); ``` -------------------------------- ### Filter Queryable Projections with QueryKit Source: https://github.com/pdevito3/querykit/blob/main/README.md Shows how to apply QueryKit filters to `IQueryable` projections, particularly when working with DTOs. This example includes configuring QueryKit to map specific DTO properties to query names for filtering, enabling flexible filtering on projected data. ```csharp var input = $"info @=* \"{fakeAuthorOne.Name}\" "; var config = new QueryKitConfiguration(config => { config.Property(x => x.AuthorInfo).HasQueryName("info"); }); var queryableRecipe = testingServiceScope.DbContext().Recipes .Include(x => x.Author) .Select(x => new RecipeDto { Id = x.Id, Title = x.Title, AuthorName = x.Author.Name, AuthorInfo = x.Author.Name + " - " + x.Author.InternalIdentifier }); var appliedQueryable = queryableRecipe.ApplyQueryKitFilter(input, config); var recipes = await appliedQueryable.ToListAsync(); ``` -------------------------------- ### Configure property mappings, aliases, and custom operators with QueryKit (C#) Source: https://context7.com/pdevito3/querykit/llms.txt Shows how to set up QueryKitConfiguration to map class properties to query names, restrict filtering/sorting on sensitive fields, and customize operator symbols. Includes examples of applying filters and sorts using the configured settings. Requires the QueryKit library and an Entity Framework DbContext. ```csharp using QueryKit; using QueryKit.Configuration; using QueryKit.Operators; public class Person { public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } public string SensitiveData { get; set; } } // Property aliases and permissions var config = new QueryKitConfiguration(settings => { // Create alias for external query names settings.Property(x => x.FirstName) .HasQueryName("first"); settings.Property(x => x.LastName) .HasQueryName("last"); // Prevent filtering or sorting on sensitive properties settings.Property(x => x.SensitiveData) .PreventFilter() .PreventSort(); }); var filterInput = """first == \"Jane\" && last == \"Doe\" """; var people = dbContext.People .ApplyQueryKitFilter(filterInput, config) .ApplyQueryKitSort("first, -Age", config) .ToList(); // Custom operators var customConfig = new QueryKitConfiguration(settings => { settings.EqualsOperator = "eq"; settings.NotEqualsOperator = "neq"; settings.GreaterThanOperator = "gt"; settings.LessThanOperator = "lt"; settings.AndOperator = "and"; settings.OrOperator = "or"; settings.CaseInsensitiveAppendix = "i"; }); var customFilter = """FirstName eqi \"jane\" and Age gt 25"""; var customResults = dbContext.People .ApplyQueryKitFilter(customFilter, customConfig) .ToList(); // Allow unknown properties (ignore unrecognized property names) var lenientConfig = new QueryKitConfiguration(settings => { settings.AllowUnknownProperties = true; }); ``` -------------------------------- ### Define Custom Business Logic Operations in C# Source: https://context7.com/pdevito3/querykit/llms.txt Encapsulates complex filtering logic accessing related data, performing calculations, or implementing domain-specific rules with automatic type conversion. Includes examples for recent sales performance, VIP customer detection, and discount eligibility. ```csharp using QueryKit; using QueryKit.Configuration; using QueryKit.Operators; public class Book { public string Title { get; set; } public decimal Price { get; set; } public List Orders { get; set; } } public class Order { public DateTime OrderDate { get; set; } public int Quantity { get; set; } } public class Customer { public string FirstName { get; set; } public decimal TotalPurchases { get; set; } public int AccountAge { get; set; } } // Custom operations with related data access var config = new QueryKitConfiguration(settings => { // Check recent sales performance settings.CustomOperation((book, op, value) => book.Orders .Where(order => order.OrderDate > DateTime.UtcNow.AddDays(-10)) .Sum(order => order.Quantity) > (int)value) .HasQueryName("RecentSales"); // VIP customer detection with multiple criteria settings.CustomOperation((customer, op, value) => (bool)value ? (customer.TotalPurchases > 10000 && customer.AccountAge > 365 && customer.FirstName.Contains("VIP")) : !(customer.TotalPurchases > 10000 && customer.AccountAge > 365 && customer.FirstName.Contains("VIP"))) .HasQueryName("IsVipCustomer"); // Discount eligibility with price threshold settings.CustomOperation((book, op, value) => book.Price > (decimal)value && book.Orders.Count > 100) .abitsQueryName("DiscountEligible"); }); // Use custom operations in filters var recentBestsellers = dbContext.Books .ApplyQueryKitFilter("RecentSales > 100", config) .ToList(); var vipCustomers = dbContext.Customers .ApplyQueryKitFilter("IsVipCustomer == true", config) .ToList(); var discountBooks = dbContext.Books .ApplyQueryKitFilter("DiscountEligible > 50.00", config) .ToList(); // Combine with standard filters var complexFilter = """RecentSales > 50 && Title @=* \"Programming\" """; var trendingProgrammingBooks = dbContext.Books .ApplyQueryKitFilter(complexFilter, config) .ToList(); ``` -------------------------------- ### Querying Nested Object Properties with Aliases (C#) Source: https://github.com/pdevito3/querykit/blob/main/README.md This example shows how to query properties of nested objects in C# using QueryKit. It includes defining nested classes, querying nested property values directly, and using custom aliases for nested properties via `HasQueryName` configuration. ```csharp 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; } } // Querying nested property var input = $"Email.Value == \"{value}\" "; // Querying with an alias var input = $"email == \"hello@gmail.com\" "; var config = new QueryKitConfiguration(config => { config.Property(x => x.Email.Value).HasQueryName("email"); }); ``` -------------------------------- ### Use 'in' operator for filtering Source: https://github.com/pdevito3/querykit/blob/main/README.md Applies the 'in' operator to filter values within a specified list. Supports multiple data types including integers, strings, and GUIDs. ```csharp var input = """(Age ^^ [20, 30, 40]) && (BirthMonth ^^* [\"January\", \"February\", \"March\"]) || (Id ^^ [\"6d623e92-d2cf-4496-a2df-f49fa77328ee\"])"""; ``` -------------------------------- ### Filter Enums by Integer Value (C#) Source: https://github.com/pdevito3/querykit/blob/main/README.md Filters using enum properties by their corresponding integer values. The example shows filtering by 'BirthMonth' using the integer '1', which corresponds to 'January' in the provided `BirthMonthEnum`. This allows direct numeric comparison for enum fields. ```csharp var input = "BirthMonth == 1"; public enum BirthMonthEnum { January = 1, February = 2, //... } ``` -------------------------------- ### Define derived/computed properties for querying with QueryKit (C#) Source: https://context7.com/pdevito3/querykit/llms.txt Demonstrates defining derived properties in QueryKitConfiguration for virtual fields like full name, working age, total compensation, and calculated age, enabling filtering and sorting on these computed values. Shows usage examples for applying filters and sorts with derived properties. Requires QueryKit and an appropriate entity model. ```csharp using QueryKit; using QueryKit.Configuration; public class Person { public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } public DateTime BirthDate { get; set; } public decimal BaseSalary { get; set; } public decimal Bonus { get; set; } } // Derived properties for filtering var config = new QueryKitConfiguration(settings => { // Concatenate properties settings.DerivedProperty(p => p.FirstName + " " + p.LastName) .HasQueryName("fullname"); // Boolean expressions settings.DerivedProperty(p => p.Age >= 18 && p.Age <= 65) .HasQueryName("working_age"); // Arithmetic calculations settings.DerivedProperty(p => p.BaseSalary + p.Bonus) .HasQueryName("total_compensation"); // Date calculations settings.DerivedProperty(p => DateTime.UtcNow.Year - p.BirthDate.Year) .HasQueryName("calculated_age"); }); // Filter using derived properties var fullNameFilter = """fullname @=* \"John Doe\""""; var byName = dbContext.People .ApplyQueryKitFilter(fullNameFilter, config) .ToList(); var workingAgeFilter = """working_age == true"""; var workingAgePeople = dbContext.People .ApplyQueryKitFilter(workingAgeFilter, config) .ToList(); var compensationFilter = """total_compensation > 100000"""; var highEarners = dbContext.People .ApplyQueryKitFilter(compensationFilter, config) .ToList(); // Derived properties also work with sorting var sortByDerived = dbContext.People .ApplyQueryKitSort("fullname, total_compensation desc", config) .ToList(); ``` -------------------------------- ### Apply filter with advanced configuration Source: https://github.com/pdevito3/querykit/blob/main/README.md Demonstrates a filter with advanced configuration options, including renaming properties and preventing sorting. ```csharp var config = new QueryKitConfiguration(config => { config.Property(x => x.FirstName) .HasQueryName("first") .PreventSort(); }); var people = _dbContext.People .ApplyQueryKitFilter(@$"first == \"Jane\" && Age < 10", config) .ToList(); ``` -------------------------------- ### Configure SoundEx for DbContext in QueryKit (C#) Source: https://github.com/pdevito3/querykit/blob/main/README.md Set up a `DbContext` to support the SoundEx algorithm for fuzzy string matching in QueryKit. This involves defining a `DbFunction` for `SOUNDEX` and potentially adding database extensions like `fuzzystrmatch` for PostgreSQL. ```csharp public class ExampleDbContext : DbContext { public ExampleDbContext(DbContextOptions options) : base(options) { } [DbFunction (Name = "SOUNDEX", IsBuiltIn = true)] public static string SoundsLike(string query) => throw new NotImplementedException(); public DbSet MyPeople { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.HasPostgresExtension("fuzzystrmatch"); } } ``` -------------------------------- ### Implement Base Custom QueryKitConfiguration in C# Source: https://github.com/pdevito3/querykit/blob/main/README.md Provides a base class for creating custom QueryKit configurations, allowing developers to define a consistent set of custom operators and settings across their application. ```csharp public class CustomQueryKitConfiguration : QueryKitConfiguration { public CustomQueryKitConfiguration(Action? configureSettings = null) : base(settings => { settings.EqualsOperator = "eq"; settings.NotEqualsOperator = "neq"; settings.GreaterThanOperator = "gt"; settings.GreaterThanOrEqualOperator = "gte"; settings.LessThanOperator = "lt"; settings.LessThanOrEqualOperator = "lte"; settings.ContainsOperator = "ct"; settings.StartsWithOperator = "sw"; settings.EndsWithOperator = "ew"; settings.NotContainsOperator = "nct"; settings.NotStartsWithOperator = "nsw"; settings.NotEndsWithOperator = "new"; settings.AndOperator = "and"; settings.OrOperator = "or"; settings.CaseInsensitiveAppendix = "i"; configureSettings?.Invoke(settings); }) { } } // --- Usage Example --- var input = """Title eq$ \"Pancakes\" and Rating gt 10"" "; var config = new CustomQueryKitConfiguration(); var filterExpression = FilterParser.ParseFilter(input, config); // Note: Spaces must be used around the comparison operator when using custom values. // `Title @@$ "titilating"` ✅ // `Title@@$"titilating"` ❌ ``` -------------------------------- ### Apply filter and sort with configuration Source: https://github.com/pdevito3/querykit/blob/main/README.md Applies both filtering and sorting using custom configurations. Sorts by 'first' ascending and 'Age' descending. ```csharp var filterInput = """first == \"Jane\" && Age > 10"""; var config = new QueryKitConfiguration(config => { config.Property(x => x.FirstName).HasQueryName("first"); }); var people = _dbContext.People .ApplyQueryKitFilter(filterInput, config) .ApplyQueryKitSort("first, Age desc", config) .ToList(); ``` -------------------------------- ### Customize Property Filtering with Aliases and Prevention (C#) Source: https://github.com/pdevito3/querykit/blob/main/README.md Demonstrates customizing property filtering using `QueryKitConfiguration`. It shows how to alias a property ('FirstName' to 'first') using `HasQueryName` and how to prevent filtering on another property ('Age') using `PreventFilter`. The input string reflects these configurations. ```csharp var input = $"""first == \"Jane\" || Age > 10"""; var config = new QueryKitConfiguration(config => { config.Property(x => x.FirstName) .HasQueryName("first"); config.Property(x => x.Age) .PreventFilter(); }); ``` -------------------------------- ### ApplyQueryKitSort - Sort IQueryable collections Source: https://context7.com/pdevito3/querykit/llms.txt Parses a sort string with comma-separated property names and directions, applying multi-level sorting to IQueryable collections. Supports ascending/descending order and sieve-style syntax. ```APIDOC ## ApplyQueryKitSort - Sort IQueryable collections ### Description Extension method that parses a sort string with comma-separated property names and directions, applying multi-level sorting to IQueryable collections. Supports ascending/descending order and sieve-style syntax. ### Method Extension Method (operates on IQueryable) ### Endpoint N/A (Extension Method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```csharp // Example usage with a Person class and Entity Framework Core DbContext var sortInput = "LastName"; var sortedPeople = dbContext.People .ApplyQueryKitSort(sortInput) .ToList(); var multiSort = "LastName asc, Age desc, FirstName"; var complexSorted = dbContext.People .ApplyQueryKitSort(multiSort) .ToList(); var sieveSort = "LastName, -Age, FirstName"; // Sieve-style syntax with minus prefix for descending var sieveSorted = dbContext.People .ApplyQueryKitSort(sieveSort) .ToList(); // Combined with filtering var filterInput = "Age > 25"; var sortInputCombined = "LastName desc, FirstName asc"; var filteredAndSorted = dbContext.People .ApplyQueryKitFilter(filterInput) .ApplyQueryKitSort(sortInputCombined) .ToList(); ``` ### Response #### Success Response (200) Returns the sorted IQueryable collection. #### Response Example (Dependent on the input collection and sort order) ```json [ { "LastName": "Smith", "FirstName": "Alice", "Age": 35 // ... other properties } ] ``` ``` -------------------------------- ### QueryKit FilterParser for Manual Expression Building Source: https://context7.com/pdevito3/querykit/llms.txt Provides direct access to QueryKit's FilterParser, allowing manual manipulation of filter strings into LINQ expressions. This is for advanced scenarios. It requires the QueryKit NuGet package and System.Linq.Expressions. Input is a filter string and optional configuration, and the output is a compiled Expression. ```csharp using QueryKit; using System.Linq.Expressions; public class Person { public string Name { get; set; } public int Age { get; set; } } // Parse filter string into expression var filterInput = "Name == \"John\" && Age > 25"; Expression> expression = FilterParser.ParseFilter(filterInput); // Use the expression with LINQ var people = new List { new Person { Name = "John", Age = 30 }, new Person { Name = "Jane", Age = 20 }, new Person { Name = "John", Age = 18 } }; var filtered = people.Where(expression.Compile()).ToList(); // Parse with configuration var config = new QueryKitConfiguration(settings => { settings.Property(x => x.Name).HasQueryName("fullname"); }); var configuredFilter = "fullname == \"John\" "; var configuredExpression = FilterParser.ParseFilter(configuredFilter, config); // Use expression with Entity Framework var dbResults = dbContext.People.Where(configuredExpression).ToList(); // Inspect the generated expression Console.WriteLine(expression.ToString()); // Output: x => ((x.Name == "John") AndAlso (x.Age > 25)) ``` -------------------------------- ### Configure Custom Operators in C# Source: https://github.com/pdevito3/querykit/blob/main/README.md Shows how to define custom comparison operators and case-insensitive appendices for filtering expressions in QueryKit. This allows for more flexible and customized query syntax. ```csharp var config = new QueryKitConfiguration(config => { config.EqualsOperator = "@@$"; config.CaseInsensitiveAppendix = "$"; config.AndOperator = "and"; }); ``` -------------------------------- ### ApplyQueryKit - Apply filtering and sorting Source: https://context7.com/pdevito3/querykit/llms.txt Extension method that applies both filtering and sorting operations using a QueryKitData object, streamlining the query pipeline. Allows for custom configurations like property mappings. ```APIDOC ## ApplyQueryKit - Apply filtering and sorting ### Description Extension method that applies both filtering and sorting operations using a QueryKitData object, streamlining the query pipeline. Allows for custom configurations like property mappings. ### Method Extension Method (operates on IQueryable) ### Endpoint N/A (Extension Method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **queryKitData** (QueryKitData) - Required - An object containing filter, sort, and optional configuration settings. - **Filters** (string) - Optional - The filter string to apply. - **SortOrder** (string) - Optional - The sort order string to apply. - **Configuration** (QueryKitConfiguration) - Optional - Custom configuration for property mappings. ### Request Example ```csharp using QueryKit; using QueryKit.Configuration; // Example usage with a Person class and Entity Framework Core DbContext // Combined filtering and sorting var queryKitData = new QueryKitData { Filters = "FirstName == \"Jane\" && Age > 25", SortOrder = "Age desc, LastName" }; var results = dbContext.People .ApplyQueryKit(queryKitData) .ToList(); // With configuration for property mappings var config = new QueryKitConfiguration(settings => { settings.Property(x => x.FirstName).HasQueryName("first"); settings.Property(x => x.LastName).HasQueryName("last"); }); var customQueryData = new QueryKitData { Filters = "first == \"Jane\" && Age > 25", SortOrder = "Age desc, last", Configuration = config }; var customResults = dbContext.People .ApplyQueryKit(customQueryData) .ToList(); ``` ### Response #### Success Response (200) Returns the IQueryable collection with both filtering and sorting applied. #### Response Example (Dependent on the input collection and QueryKitData settings) ```json [ { "FirstName": "Jane", "LastName": "Doe", "Age": 30 // ... other properties } ] ``` ``` -------------------------------- ### Sort IQueryable Collections with String Syntax using QueryKit Source: https://context7.com/pdevito3/querykit/llms.txt The ApplyQueryKitSort extension method parses a sort string containing comma-separated property names and directions. It applies multi-level sorting to IQueryable collections, supporting explicit ascending/descending keywords and a Sieve-style syntax with a minus prefix for descending order. This method is useful for dynamic sorting based on user preferences or API parameters. ```csharp using QueryKit; // Simple ascending sort (default) var sortInput = "LastName"; var sortedPeople = dbContext.People .ApplyQueryKitSort(sortInput) .ToList(); // Multiple properties with explicit directions var multiSort = "LastName asc, Age desc, FirstName"; var complexSorted = dbContext.People .ApplyQueryKitSort(multiSort) .ToList(); // Sieve-style syntax with minus prefix for descending var sieveSort = "LastName, -Age, FirstName"; var sieveSorted = dbContext.People .ApplyQueryKitSort(sieveSort) .ToList(); // Combined with filtering var filterInput = """Age > 25""" var sortInput = "LastName desc, FirstName asc"; var filteredAndSorted = dbContext.People .ApplyQueryKitFilter(filterInput) .ApplyQueryKitSort(sortInput) .ToList(); ``` -------------------------------- ### Apply SoundEx Filtering with QueryKit Configuration (C#) Source: https://github.com/pdevito3/querykit/blob/main/README.md Utilize the SoundEx operator (`~~`) within QueryKit to perform fuzzy matching on string properties. This requires specifying the `DbContext` type in the `QueryKitConfiguration` to enable the SoundEx functionality. ```csharp var input = $"""LastName ~~ \"devito\" """; // Act var queryablePeople = testingServiceScope.DbContext().People; var appliedQueryable = queryablePeople.ApplyQueryKitFilter(input, new QueryKitConfiguration(o => { o.DbContextType = typeof(TestingDbContext); })); var people = await appliedQueryable.ToListAsync(); ``` -------------------------------- ### Comparison Operators for Comprehensive Filtering in C# Source: https://context7.com/pdevito3/querykit/llms.txt Provides extensive comparison operators for filtering, including case-sensitive and case-insensitive variants, collection operators, and count operators. ```csharp using QueryKit; public class Product { public string Name { get; set; } public string Description { get; set; } public decimal Price { get; set; } public int Stock { get; set; } public List Tags { get; set; } public List Reviews { get; set; } } public class Review { public int Rating { get; set; } public string Comment { get; set; } } // Equality operators var exactMatch = """Name == \"Widget\" """; var notMatch = """Name != \"Widget\" """; var caseInsensitiveMatch = """Name ==* \"WIDGET\" """; // String operators var contains = """Description @= \"premium\" """; var containsInsensitive = """Description @=* \"PREMIUM\" """; var startsWith = """Name _= \"Pro\" """; var startsWithInsensitive = """Name _=* \"pro\" """; var endsWith = """Name _-= \"2023\" """; var notContains = """Description !@= \"discount\" """; // Numeric comparison operators var greaterThan = """Price > 99.99"""; var lessThan = """Stock < 10"""; var greaterOrEqual = """Price >= 100.00"""; var lessOrEqual = """Stock <= 5"""; // Collection operators - In/Not In var inOperator = """Stock ^^ [5, 10, 15, 20]"""; var notInOperator = """Stock !^^ [0, 1, 2]"""; // Collection operators - Has/Does Not Have (for primitive collections) var hasTag = """Tags ^$ \"featured\" """; var hasTagInsensitive = """Tags ^$* \"FEATURED\" """; var notHasTag = """Tags !^$ \"discontinued\" """; // Count operators for collections (prefix with #) var hasReviews = """Reviews #> 0"""; var exactReviewCount = """Reviews #== 5"""; var minReviews = """Reviews #>= 10"""; var maxReviews = """Reviews #<= 100"""; var notExactCount = """Reviews #!= 0"""; // Complex combined example var complexFilter = """ (Name @=* \"widget\" || Description @=* \"tool\") && Price >= 50.00 && Price <= 200.00 && Stock > 0 && Tags ^$ \"available\" && Reviews #>= 5 """; var products = dbContext.Products .ApplyQueryKitFilter(complexFilter) .ToList(); ``` -------------------------------- ### QueryKit Support for EF Core HasConversion (C#) Source: https://github.com/pdevito3/querykit/blob/main/README.md This C# code demonstrates how QueryKit integrates with EF Core's `HasConversion` feature. It shows the EF Core configuration and the corresponding QueryKit configuration using `HasQueryName` and `HasConversion()` to filter properties converted to a different type. ```csharp // EF configuration with HasConversion builder.Property(x => x.Email) .HasConversion(x => x.Value, x => new EmailAddress(x)) .HasColumnName("email"); // QueryKit configuration for HasConversion properties var config = new QueryKitConfiguration(config => { config.Property(x => x.Email) // Point to Email property, NOT Email.Value .HasQueryName("email") .HasConversion(); // Specify the target type used in HasConversion }); // Now you can filter directly against the property: var input = "email == \"hello@gmail.com\" "; var people = _dbContext.People .ApplyQueryKitFilter(input, config) .ToList(); ``` -------------------------------- ### EF Core Nested Object Configuration for QueryKit (C#) Source: https://github.com/pdevito3/querykit/blob/main/README.md This C# snippet illustrates different Entity Framework Core configurations for nested objects (`ComplexProperty`, `HasConversion`, `OwnsOne`) and how they map to QueryKit's property mapping. It highlights the key distinction in QueryKit configuration based on the EF Core strategy used. ```csharp public sealed class PersonConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.HasKey(x => x.Id); // Option 1 (as of .NET 8) - ComplexProperty // QueryKit: config.Property(x => x.Email.Value).HasQueryName("email"); builder.ComplexProperty(x => x.Email, x => x.Property(y => y.Value) .HasColumnName("email")); // Option 2 - HasConversion (see HasConversion support below) // QueryKit: config.Property(x => x.Email).HasQueryName("email").HasConversion(); builder.Property(x => x.Email) .HasConversion(x => x.Value, x => new EmailAddress(x)) .HasColumnName("email"); // Option 3 - OwnsOne // QueryKit: config.Property(x => x.Email.Value).HasQueryName("email"); builder.OwnsOne(x => x.Email, opts => { opts.Property(x => x.Value).HasColumnName("email"); }).Navigation(x => x.Email) .IsRequired(); } } ``` -------------------------------- ### ApplyQueryKitFilter - Filter IQueryable collections Source: https://context7.com/pdevito3/querykit/llms.txt Parses a filter string and applies it to an IQueryable collection, translating the expression into efficient LINQ predicates. Supports various operators, nested properties, and collection filtering. ```APIDOC ## ApplyQueryKitFilter - Filter IQueryable collections ### Description Extension method that parses a filter string and applies it to an IQueryable collection, translating the expression into efficient LINQ predicates. Supports various operators, nested properties, and collection filtering. ### Method Extension Method (operates on IQueryable) ### Endpoint N/A (Extension Method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```csharp // Example usage with a Person class and Entity Framework Core DbContext public class Person { public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } public decimal Salary { get; set; } public DateOnly BirthDate { get; set; } public bool IsActive { get; set; } } var filterInput = "FirstName == \"Jane\" && Age > 25"; var people = dbContext.People .ApplyQueryKitFilter(filterInput) .ToList(); var complexFilter = "(FirstName == \"Jane\" || FirstName == \"John\") && (Age >= 25 && Age <= 65) && IsActive == true"; var results = dbContext.People .ApplyQueryKitFilter(complexFilter) .ToList(); var caseInsensitiveFilter = "FirstName @=* \"JANE\" "; // Contains, case-insensitive var matches = dbContext.People .ApplyQueryKitFilter(caseInsensitiveFilter) .ToList(); var dateFilter = "BirthDate >= \"1990-01-01\" && BirthDate <= \"2000-12-31\" "; var millennials = dbContext.People .ApplyQueryKitFilter(dateFilter) .ToList(); var collectionFilter = "Age ^^ [25, 30, 35, 40]"; // In operator var specificAges = dbContext.People .ApplyQueryKitFilter(collectionFilter) .ToList(); ``` ### Response #### Success Response (200) Returns the filtered IQueryable collection. #### Response Example (Dependent on the input collection and filter) ```json [ { "FirstName": "Jane", "LastName": "Doe", "Age": 30 // ... other properties } ] ``` ``` -------------------------------- ### Use parentheses for order of operations Source: https://github.com/pdevito3/querykit/blob/main/README.md Demonstrates grouping filter conditions with parentheses to control evaluation order. ```csharp var input = """(FirstName == \"Jane\" && Age < 10) || FirstName == \"John\" "; ``` -------------------------------- ### IEnumerable Filtering and Sorting with QueryKit Source: https://context7.com/pdevito3/querykit/llms.txt Shows how QueryKit can be used to filter and sort in-memory IEnumerable collections using the same syntax as IQueryable. This is useful for client-side data manipulation. It requires the QueryKit NuGet package. Inputs are filter and/or sort strings, and the output is a processed IEnumerable collection. ```csharp using QueryKit; public class Product { public string Name { get; set; } public decimal Price { get; set; } public int Stock { get; set; } public List Categories { get; set; } } // In-memory collection var products = new List { new Product { Name = "Widget Pro", Price = 99.99m, Stock = 50, Categories = new() { "tools", "premium" } }, new Product { Name = "Widget Lite", Price = 49.99m, Stock = 100, Categories = new() { "tools", "budget" } }, new Product { Name = "Gadget Ultra", Price = 199.99m, Stock = 25, Categories = new() { "electronics", "premium" } }, new Product { Name = "Gadget Basic", Price = 79.99m, Stock = 75, Categories = new() { "electronics", "budget" } } }; // Filter in-memory collections var filterInput = "Price > 50.00 && Stock >= 50"; var filtered = products .ApplyQueryKitFilter(filterInput) .ToList(); // Sort in-memory collections var sortInput = "Price desc, Name"; var sorted = products .ApplyQueryKitSort(sortInput) .ToList(); // Combined filtering and sorting var queryData = new QueryKitData { Filters = "Categories ^$ \"premium\" && Price < 150.00", SortOrder = "Price desc" }; var premiumAffordable = products .ApplyQueryKit(queryData) .ToList(); // All operators work with in-memory collections var complexFilter = "( (Name @=* \"widget\" || Name @=* \"gadget\") && Price >= 50.00 && Stock > 0 && Categories ^$ \"premium\" )"; var results = products .ApplyQueryKitFilter(complexFilter) .ToList(); ``` -------------------------------- ### Apply QueryKit Filters to Entity Framework Core Queries Source: https://github.com/pdevito3/querykit/blob/main/README.md Demonstrates how to use the `ApplyQueryKitFilter` extension method to filter data directly from Entity Framework Core DbContext. This method translates complex expressions into efficient SQL queries, supporting arithmetic operations, type conversions, and parentheses for order of operations. ```csharp // Calculate profit margin and filter var profitableItems = _dbContext.Products .ApplyQueryKitFilter("((Price - Cost) / Price) > 0.2") .ToList(); // Find orders with high shipping ratio var expensiveShipping = _dbContext.Orders .ApplyQueryKitFilter("(ShippingCost / TotalAmount) > 0.15") .ToList(); // Complex business logic in one filter var qualifiedCustomers = _dbContext.Customers .ApplyQueryKitFilter("( (TotalPurchases / NumberOfOrders) > 500 && ((LastOrderDate - FirstOrderDate) / 365) >= 2 ") .ToList(); ``` -------------------------------- ### Filter Collection by Ingredient Stock using 'All' (C#) Source: https://github.com/pdevito3/querykit/blob/main/README.md Filters a collection ensuring all ingredients meet a stock condition (e.g., stock >= 1). It uses the '%>=' operator, prefixed with '%', to signify the 'All' condition for the 'Stock' property of ingredients. This is useful for enforcing conditions across all elements in a sub-collection. ```csharp var input = """Ingredients.Stock %>= 1"""; ``` -------------------------------- ### Use logical operators in filter Source: https://github.com/pdevito3/querykit/blob/main/README.md Shows how to combine multiple filter conditions using logical operators (and '&&', or '||'). ```csharp var input = """FirstName == \"Jane\" && Age < 10"""; var input = """FirstName == \"Jane\" || FirstName == \"John\" "; ``` -------------------------------- ### Apply Filtering and Sorting Simultaneously with QueryKit Source: https://context7.com/pdevito3/querykit/llms.txt The ApplyQueryKit extension method applies both filtering and sorting operations using a QueryKitData object, which encapsulates filter strings, sort order, and optional configuration. This method streamlines the query pipeline by allowing combined filter and sort operations in a single step. It also supports custom property mappings via QueryKitConfiguration. ```csharp using QueryKit; using QueryKit.Configuration; // Combined filtering and sorting var queryKitData = new QueryKitData { Filters = """FirstName == \"Jane\" && Age > 25""", SortOrder = "Age desc, LastName" }; var results = dbContext.People .ApplyQueryKit(queryKitData) .ToList(); // With configuration for property mappings var config = new QueryKitConfiguration(settings => { settings.Property(x => x.FirstName).HasQueryName("first"); settings.Property(x => x.LastName).HasQueryName("last"); }); var customQueryData = new QueryKitData { Filters = """first == \"Jane\" && Age > 25""", SortOrder = "Age desc, last", Configuration = config }; var customResults = dbContext.People .ApplyQueryKit(customQueryData) .ToList(); ``` -------------------------------- ### Configure QueryKit to Allow Unknown Properties (C#) Source: https://github.com/pdevito3/querykit/blob/main/README.md This snippet demonstrates how to configure QueryKit to ignore unknown properties during expression resolution by setting `AllowUnknownProperties` to `true`. This is useful for loosening validation when unexpected properties might be present in the input. ```csharp var config = new QueryKitConfiguration(config => { config.AllowUnknownProperties = true; }); var filterExpression = FilterParser.ParseFilter(input, config); ``` -------------------------------- ### Filter Collection by Count using '#' Prefix (C#) Source: https://github.com/pdevito3/querykit/blob/main/README.md Filters collections based on their element count. By prefixing operators with '#', you can apply conditions to the collection's size, such as checking if the number of ingredients is greater than or equal to a certain value (e.g., 0). ```csharp var input = """Ingredients #>= 0"""; ``` -------------------------------- ### EF Core HasConversion Support with QueryKit Source: https://context7.com/pdevito3/querykit/llms.txt Demonstrates how QueryKit enables direct filtering of EF Core properties configured with HasConversion, eliminating the need to access nested values. It requires EF Core and QueryKit NuGet packages. The input is a filter string, and the output is a filtered IQueryable collection. ```csharp using QueryKit; using QueryKit.Configuration; using Microsoft.EntityFrameworkCore; public class Person { public Guid Id { get; set; } public string Name { get; set; } public EmailAddress Email { get; set; } } public class EmailAddress { public string Value { get; private set; } public EmailAddress(string value) { Value = value; } } // Entity Framework configuration public class PersonConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.HasKey(x => x.Id); // Configure HasConversion to store EmailAddress as string builder.Property(x => x.Email) .HasConversion( email => email.Value, value => new EmailAddress(value)) .HasColumnName("email"); } } // QueryKit configuration for HasConversion property var config = new QueryKitConfiguration(settings => { settings.Property(x => x.Email) .HasQueryName("email") .HasConversion(); // Specify target type from HasConversion }); // Filter directly against the property (no need for .Value access) var filterInput = "email == \"john@example.com\" "; var people = dbContext.People .ApplyQueryKitFilter(filterInput, config) .ToList(); // Case-insensitive filtering var caseInsensitive = "email @=* \"JOHN@EXAMPLE.COM\" "; var matches = dbContext.People .ApplyQueryKitFilter(caseInsensitive, config) .ToList(); // String operators work seamlessly var domainFilter = "email _-= \"@example.com\" "; var exampleUsers = dbContext.People .ApplyQueryKitFilter(domainFilter, config) .ToList(); ``` -------------------------------- ### Expose Derived Properties for Filtering (C#) Source: https://github.com/pdevito3/querykit/blob/main/README.md Shows how to expose custom derived properties for filtering using `QueryKitConfiguration`. `DerivedProperty` allows creating aliases for computed values, such as combining first and last names ('fullname') or creating boolean flags based on conditions ('adult_johns'). These derived properties can then be used in the input query string. ```csharp var config = new QueryKitConfiguration(config => { config.DerivedProperty(p => p.FirstName + " " + p.LastName).HasQueryName("fullname"); config.DerivedProperty(p => p.Age >= 18 && p.FirstName == "John").HasQueryName("adult_johns"); }); var input = $"""(fullname @=* \"John Doe\") && age >= 18"""; // or var input = $"""adult_johns == true""""; } ] } ] } ``` ``` -------------------------------- ### Parse Sort Strings into Expressions in C# Source: https://context7.com/pdevito3/querykit/llms.txt This code demonstrates parsing sort strings into LINQ expressions for advanced manual manipulation. It depends on the QueryKit library and System.Linq.Expressions for expression building and IQueryable operations. Inputs include a sort string like 'LastName asc, Age desc', producing a list of sort expressions that can be iteratively applied; limitations include the need for manual looping over multiple sort criteria and direct handling of ascending/descending sorts. ```csharp using QueryKit; using System.Linq.Expressions; public class Person { public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } } // Parse sort string into expression list var sortInput = "LastName asc, Age desc, FirstName"; var sortExpressions = SortParser.ParseSort(sortInput); // Manually apply sort expressions var people = new List { new Person { FirstName = "John", LastName = "Doe", Age = 30 }, new Person { FirstName = "Jane", LastName = "Doe", Age = 25 }, new Person { FirstName = "Bob", LastName = "Smith", Age = 35 } }; var queryable = people.AsQueryable(); var firstSort = sortExpressions[0]; var ordered = firstSort.IsAscending ? queryable.OrderBy(firstSort.Expression) : queryable.OrderByDescending(firstSort.Expression); for (int i = 1; i < sortExpressions.Count; i++) { var sort = sortExpressions[i]; ordered = sort.IsAscending ? ordered.ThenBy(sort.Expression) : ordered.ThenByDescending(sort.Expression); } var sorted = ordered.ToList(); ``` -------------------------------- ### Filter Nested Collections with Custom Query Name (C#) Source: https://github.com/pdevito3/querykit/blob/main/README.md Filters based on properties within nested collections, like preparations within ingredients. It requires a `QueryKitConfiguration` to map the nested property path to a custom query name ('preparations'). The input string then uses this alias for filtering. ```csharp var input = $"""preparations == \"{preparationOne.Text}\" """; var config = new QueryKitConfiguration(settings => { settings.Property(x => x.Ingredients .SelectMany(y => y.Preparations) .Select(y => y.Text)) .HasQueryName("preparations"); }); // Act var queryableRecipes = testingServiceScope.DbContext().Recipes; var appliedQueryable = queryableRecipes.ApplyQueryKitFilter(input, config); var recipes = await appliedQueryable.ToListAsync(); ```