QueryX 2.1.1
dotnet add package QueryX --version 2.1.1
NuGet\Install-Package QueryX -Version 2.1.1
<PackageReference Include="QueryX" Version="2.1.1" />
paket add QueryX --version 2.1.1
#r "nuget: QueryX, 2.1.1"
// Install QueryX as a Cake Addin #addin nuget:?package=QueryX&version=2.1.1 // Install QueryX as a Cake Tool #tool nuget:?package=QueryX&version=2.1.1
QueryX
QueryX allows performing filtering, paging and sorting to IQueryable ends using URL query strings.
Installation
Install with nuget:
Install-Package QueryX
Usage
A filter model is needed to define the properties that will be used for filtering, this model could be an specific filter class, a Dto or a Domain model object.
public class Card
{
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public int Priority { get; set; }
public float EstimatedPoints { get; set; }
public List<User> Owners { get; set; }
}
By default all properties can be used for filtering and sorting, this could be customized using fluent configuration.
Example
QueryX adds ApplyQuery
extension methods to IQueryable interface to perform queries:
var filter = "priority > 1";
var result = _context.Set<Card>().ApplyQuery(filter).ToList();
Filtering
Filtering is made using operators, so a filter is defined this way: propertyName operator value
.
It is possible to combine multiple filters using "and" (&
) and "or" (|
) logical operators:
id>1 & title=-'test' | priority|=1,2
For facilitating writing queries in URL, ;
(semicolon) character can be used instead for representing the and logical operator:
id>1 ; title=-'test' | priority|=1,2
Filter grouping
Filters can be also grouped using parentheses to determine how they should be evaluated:
id>1 ; (title=-'test' | priority|=1,2)
Collection filters
It is possible to specify filters for collection properties with the following syntax:
propertyName(childPropertyName operator value)
The above code will use the Enumerable.Any
method for applying the conditions.
For using the Enumerable.All
method:
propertyName*(childPropertyName operator value)
An example using the Card
object would be:
owners(id==1 | name=='user2')
Supported value types
Category | Description |
---|---|
Numbers | integer, float, real, etc. |
String, Char | should be wrapped in single quotes |
DateTime, Timespan | should be wrapped in single quotes |
Enums | should be wrapped in single quotes |
Constants | true, false, null |
Operators
Operator | Description | Comment |
---|---|---|
== | Equal operator | |
!= | Not equal | |
< | Less than | |
⇐ | Less than or equal | |
> | Greater than | |
>= | Greater than or equal | |
-=- | Contains | String type only |
=- | Starts with | String type only |
-= | Ends with | String type only |
|= | In | Allows multiple values |
Multiple values are specified this way: 0,1,2
or 'val1','val2','val3'
if the values are strings
Case insensitive operator
All operators can be combined with the case insensitive operator (*
) for ignoring case when comparing strings:
title ==* 'TeSt VaLuE'
This operator is intended to work only with string properties
Not Operator
The not operator (!
) can be applied to any filter, collection filter or group:
!id>1 ; !title=-'test' | !priority|=1,2
id>1 ; !(title=-'test' | priority|=1,2)
!owners(id==1 | name=='user2')
Sorting and Paging
The ApplyOrderingAndPaging
method allow specifying ordering.
For ascending order base on property Title
:
title
For descending order:
-title
It is possible to combine multiple orderings:
id,-priority,title
Example:
var sortBy = "-estimatedPoints";
var offset = 10;
var limit = 10;
_context.Set<Card>().ApplyOrderingAndPaging(sortBy, offset, limit);
Customize filtering and sorting
It is possible to customize the filtering behavior with QueryMappingConfig
class:
QueryMappingConfig.Global
.For<Card>(cfg =>
{
// mapping configurations
});
Map property name:
Allows mapping a property with a different name that will appear in the filter
or sortBy
string:
cfg.Property(c => c.Priority).MapFrom("queryPriority");
cfg.Property(c => c.Board.Title).MapFrom("bTitle");
Additionally, MapFrom
method supports a second parameter to apply custom conversion from string to the property type:
cfg.Property(c => c.Priority).MapFrom("queryPriority", value => int.ParseInt(value));
Ignore properties:
Ignore properties from filter and sorting steps. IgnoreFilter
and IgnoreSort
methods exists also.
cfg.Property(c => c.Priority).Ignore();
Custom filters:
This properties are excluded as part of the filter, custom code needs to be written for doing something with the filter values. Custom filters are applied after all filters have been applied
cfg.Property(c => c.Priority).CustomFilter((source, values, op) =>
{
// source : IQueryable instance to apply the custom filter
// values : values specified in filter string
// op : operator for this filter
return source.Where(c => c.Priority == values[0]);
});
Custom sort:
This properties are excluded as part of the sort behavior, custom code needs to be written to apply them. Custom filters are applied after all filters have been applied
cfg.Property(c => c.Priority).CustomSort((source, ascending, isOrdered) =>
{
// source : IQueryable instance to apply the custom filter
// ascending: indicates if the sorting should be done in ascending direction
// isOrdered: indicates if the IQueryable instace have been already ordered, if true, ThenBy and ThenByDescending methods should be used as appropriate
return isOrdered
? ascending
? source.ThenBy(c => c.Priority)
: source.ThenByDescending(c => c.Priority)
: ascending
? source.OrderBy(c => c.Priority)
: source.OrderByDescending(c => c.Priority);
});
Concatenate configurations:
Configurations can be concatenated as required:
cfg.Property(c => c.Priority).MapFrom("queryPriority").Ignore();
cfg.Property(c => c.Board.Title).MapFrom("bTitle").CustomFilter((source, values, op) =>
{
// ...
});
Override global configurations
The configurations created using QueryMappingConfig.Global
are applied globally. ApplyQuery
and ApplyOrderingAndPaging
methods accepts a QueryMappingConfig
instance in case specific configuration is needed:
var config = new QueryMappingConfig();
config.For<Card>(cfg =>
{
// set specific configurations
});
var filter = "id |= 2,4,6";
_context.Set<Card>().ApplyQuery(filter, mappingConfig: config);
Extending global configuration is also possible:
var config = QueryMappingConfig.Global.Clone()
config.For<Card>(cfg =>
{
// set specific configurations
});
var filter = "id |= 2,4,6";
_context.Set<Card>().ApplyQuery(filter, mappingConfig: config);
QueryModel
QueryModel
is a class that can be used to capture user parameters in a WebAPI endpoint, it contains Filter
, SortBy
, Offset
and Limit
properties. ApplyQuery
and ApplyOrderingAndPaging
methods have overloads to receive a QueryModel
instance.
Query exceptions
By default invalid properties will be ignored for filtering and ordering but it is possible to change this behavior by calling ThrowQueryExceptions()
when registering QueryX:
builder.Services.AddQueryX(o => o.ThrowQueryExceptions(false));
These exceptions will be thrown as appropriate:
InvalidFilterPropertyException
for filtering errorsInvalidOrderingPropertyException
for ordering errors
It is also possible set this configuration using QueryMappingConfig:
QueryMappingConfig.Global
.SetQueryConfiguration(options => options.ThrowQueryExceptions(true));
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. 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. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.CSharp (>= 4.7.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 6.0.0)
- Superpower (>= 3.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
2.1.1 | 1,682 | 3/25/2024 |
2.1.0 | 561 | 12/7/2023 |
2.0.0 | 808 | 11/11/2023 |
2.0.0-beta.4 | 76 | 11/11/2023 |
2.0.0-beta.3 | 147 | 11/5/2023 |
2.0.0-beta.2 | 180 | 10/28/2023 |
2.0.0-beta.1 | 79 | 10/26/2023 |
2.0.0-alpha-02 | 81 | 10/22/2023 |
2.0.0-alpha-01 | 88 | 10/22/2023 |
1.2.0 | 233 | 9/16/2023 |
1.1.0 | 265 | 9/8/2023 |
1.0.2 | 628 | 5/3/2023 |
1.0.1 | 143 | 4/26/2023 |
1.0.0 | 403 | 10/6/2022 |
1.0.0-beta-0007 | 106 | 10/4/2022 |
1.0.0-beta-0006 | 163 | 9/28/2022 |
1.0.0-beta-0005 | 143 | 9/17/2022 |
1.0.0-beta-0004 | 189 | 9/14/2022 |
1.0.0-beta-0003 | 116 | 9/13/2022 |
1.0.0-beta-0001 | 110 | 9/10/2022 |
1.0.0-alpha-0002 | 110 | 9/9/2022 |
1.0.0-alpha-0001 | 108 | 9/8/2022 |