Ooze.Typed is a .NET library that simplifies data querying in your applications by providing a strongly-typed approach to filtering, sorting, and paging operations on IQueryable<T>
sources. Key features of library are:
- Strongly-typed filters/sorters
- Pagination
- Query language - Optional support for string-based query expressions
- Async capabilities - Optional opt in async/await support
You can find latest versions on nuget on this location.
Except base Ooze.Typed
package there are few more that add additional filter extensions to the filter builder that you use in your provider implementations. These are listed below:
- Ooze.Typed.EntityFrameworkCore
- Ooze.Typed.EntityFrameworkCore.Sqlite
- Ooze.Typed.EntityFrameworkCore.SqlServer
- Ooze.Typed.EntityFrameworkCore.Npgsql
- Ooze.Typed.EntityFrameworkCore.MySql
These packages provide additional provider specific EF
extensions to the filter builder pipeline. There is another package which can be installed and it will provide query language
filtration:
In order to use Ooze you'll need to create a few things. Simple example will be shown in the subsections below.
First off, in order to be able to filter your IQueryable<T>
queries, you will need an implementation of IFilterProvider
interface, a filter type and queryable entity type. Example of this can be seen below:
public class MyClass
{
public int Id { get; set; }
}
public class MyClassFilters
{
public int Id { get; set; }
}
public class MyClassFiltersProvider : IFilterProvider<MyClass, MyClassFilters>
{
public IEnumerable<FilterDefinition<MyClass, MyClassFilters>> GetFilters()
{
return Filters.CreateFor<MyClass, MyClassFilters>()
//add equality filter onto MyClass instance over Id property and use Id property from incoming filter instance in that operation
.Equal(x => x.Id, filter => filter.Id)
//...add other filters if needed
.Build();
}
}
Additionally, if we need to support sorting of IQueryable<T>
queries, we will need implementation of ISorterProvider
which will look similar to the filter implementation. Example of sorter provider can be seen below:
public class MyClassSortersProvider : ISorterProvider<MyClass, MyClassSorters>
{
public IEnumerable<SortDefinition<MyClass, MyClassSorters>> GetSorters()
{
return Sorters.CreateFor<MyClass, MyClassSorters>()
//add sorting on Id property in provided direction from sorter instance
.SortBy(x => x.Id, sort => sort.Id)
.Build();
}
}
Next step would be to register your filter/sorter implementations in your service collection. Example of this can be seen below:
//Example for minimal apis
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOozeTyped()
.Add<MyClassFiltersProvider>()
.Add<MyClassSortersProvider>();
//Example for Startup class
public class Startup
{
...
public void ConfigureServices(IServiceCollection services)
{
services.AddOozeTyped()
.Add<MyClassFiltersProvider>()
.Add<MyClassSortersProvider>();
}
...
}
Last part of this would be to call IOperationResolver
in your code and pass it the filtering/sorting/paging options that you want to apply to your IQueryable<T>
instance. Example of this can be seen below:
//lets say you have a route which gets filters/sorters from request body
app.MapPost("/", (
DatabaseContext db,
IOperationResolver<MyEntity, MyEntityFilters, MyEntitySorters> resolver,
Input model) =>
{
IQueryable<MyEntity> query = db.Set<MyEntity>();
query = resolver
.WithQuery(query)
.Filter(model.Filters)
//you can also use .Sort(model.Sorters) or .Page(model.Paging) method, or if you don't want to sort or page or even filter something out, you can always remove the calls.
.Apply();
//query will now contain updated IQueryable<MyEntity> instance with applied filters that were passed in the request
return query;
});
//example type holding different details needed for filters/sorters/paging
public record Input(MyEntityFilters Filters, MyEntitySorters Sorters, PagingOptions Paging);
And that is it. You can define from which place you want to map/bind filters, sorters, paging. If you have a POST/PUT endpoint you can map it from request body. In case of GET request you might get it from the request url. Or in case you got some service you might manually pass the filters down to IOperationResolver
. You can use whatever suits you best here.
In case you want to see more examples and a bit more detailed documentation about each of the components be sure to check out docs
As previously mentioned additional packages contains some usefull extensions when working with specific "flavor" of EF. For example you might be using Sqlite
or SqlServer
or Postgres
etc. For these situations you can install these specific packages which contain extensions methods for the specific flavor. More about what is supported on each of the packages can be seen below.
This packages depends on EF Core packages and exposes next extensions:
Like()
- EF.Eunctions.Like
This packages depends on EF Core Sqlite package and package mentioned beforehand and exposes next extensions:
Glob()
- EF.Functions.Glob
This package depends on EF Core SqlServer package and package mentioned beforehand and exposes next extensions:
IsDate()
- EF.Functions.IsDateIsNumeric()
- EF.Functions.IsNumericContains()
- EF.Functions.ContainsIsDateDiffDay()
- EF.Functions.DateDiffDayIsDateDiffMonth()
- EF.Functions.DateDiffMonthIsDateDiffWeek()
- EF.Functions.DateDiffWeekIsDateDiffYear()
- EF.Functions.DateDiffYearIsDateDiffHour()
- EF.Functions.DateDiffHourIsDateDiffMinute()
- EF.Functions.DateDiffMinuteIsDateDiffSecond()
- EF.Functions.DateDiffSecondIsDateDiffMilisecond()
- EF.Functions.DateDiffMilisecondIsDateDiffMicrosecond()
- EF.Functions.DateDiffMicrosecondIsDateDiffNanosecond()
- EF.Functions.DateDiffNanosecond
This package depends on EF Core Npgsql package and package mentioned beforehand and exposes next extensions:
InsensitiveLike()
- EF.Functions.ILikeSoundexEqual()
- EF.Functions.FuzzyStringMatchSoundex
This package depends on EF Core MySql (Pomelo) package and package mentioned beforehand and exposes next extensions:
IsDateDiffDay()
- EF.Functions.DateDiffDayIsDateDiffMonth()
- EF.Functions.DateDiffMonthIsDateDiffYear()
- EF.Functions.DateDiffYearIsDateDiffHour()
- EF.Functions.DateDiffHourIsDateDiffMinute()
- EF.Functions.DateDiffMinuteIsDateDiffSecond()
- EF.Functions.DateDiffSecondIsDateDiffMicrosecond()
- EF.Functions.DateDiffMicrosecond