Sieve/README.md

158 lines
6.5 KiB
Markdown
Raw Normal View History

2018-01-27 09:09:01 +01:00
# 🎛️ Sieve
2018-01-27 13:20:00 +01:00
Sieve is a simple, clean, and extensible framework for .NET Core that **adds sorting, filtering, and pagination functionality out of the box**.
2018-01-27 09:09:01 +01:00
Most common use case would be for serving ASP.NET Core GET queries.
2018-01-28 00:46:59 +01:00
[![NuGet Pre Release](https://img.shields.io/nuget/v/Sieve.svg?style=flat-square)](https://www.nuget.org/packages/Sieve)
2018-01-28 01:08:08 +01:00
[Get Sieve on nuget](https://www.nuget.org/packages/Sieve/)
2018-01-28 00:46:59 +01:00
2018-01-27 09:09:01 +01:00
## Usage for ASP.NET Core
In this example, consider an app with a `Post` entity.
We'll use Sieve to add sorting, filtering, and pagination capabilities when GET-ing all available posts.
2018-01-28 00:54:13 +01:00
### 1. Add required services
2018-01-27 09:09:01 +01:00
Inject the `SieveProcessor<TEntity>` service for each entity you'd like to use Sieve with.
2018-01-27 13:20:00 +01:00
So to use Sieve with `Post`s, in `ConfigureServices` in `Startup.cs` add:
2018-01-27 09:09:01 +01:00
```
services.AddScoped<SieveProcessor<Post>>();
```
2018-01-28 00:54:13 +01:00
### 2. Tell Sieve which properties you'd like to sort/filter in your models
2018-01-27 09:09:01 +01:00
Sieve will only sort/filter properties that have the attribute `[Sieve(CanSort = true, CanFilter = true)]` on them (they don't have to be both true).
2018-01-27 13:20:00 +01:00
So for our `Post` entity model example:
2018-01-27 09:09:01 +01:00
```
public int Id { get; set; }
[Sieve(CanFilter = true, CanSort = true)]
public string Title { get; set; }
[Sieve(CanFilter = true, CanSort = true)]
public int LikeCount { get; set; }
[Sieve(CanFilter = true, CanSort = true)]
public int CommentCount { get; set; }
[Sieve(CanFilter = true, CanSort = true, name = "created")]
public DateTimeOffset DateCreated { get; set; } = DateTimeOffset.UtcNow;
```
There is also the `name` parameter that you can use to have a different name for use by clients.
2018-01-28 00:54:13 +01:00
### 3. Get sort/filter/page queries by using the Sieve model in your controllers
2018-01-27 09:09:01 +01:00
2018-01-28 00:54:13 +01:00
In the action that handles returning Posts, use `SieveModel` to get the sort/filter/page query.
2018-01-27 13:20:00 +01:00
Apply it to your data by injecting `SieveProcessor<Post>` into the controller and using its `ApplyAll` method.
2018-01-27 09:09:01 +01:00
For instance:
```
[HttpGet]
public JsonResult GetPosts(SieveModel sieveModel)
{
var result = _dbContext.Posts.AsNoTracking(); // Makes read-only queries faster
2018-01-28 00:54:13 +01:00
result = _sieveProcessor.ApplyAll(sieveModel, result); // Returns `result` after applying the sort/filter/page query in `SieveModel` to it
2018-01-27 09:09:01 +01:00
return Json(result.ToList());
}
```
There are also `ApplySorting`, `ApplyFiltering`, and `ApplyPagination` methods.
2018-01-27 12:49:02 +01:00
### 4. Send a request
2018-01-27 09:09:01 +01:00
2018-01-27 12:51:00 +01:00
[Send a request](#send-a-request)
2018-01-27 09:09:01 +01:00
2018-01-27 12:49:02 +01:00
### Add custom sort/filter methods
2018-01-27 09:09:01 +01:00
2018-01-27 09:33:48 +01:00
If you want to add custom sort/filter methods, inject `ISieveCustomSortMethods<TEntity>` or `ISieveCustomFilterMethods<TEntity>` with the implementation being a class that has custom sort/filter methods for `TEntity`.
2018-01-27 09:09:01 +01:00
2018-01-27 09:33:48 +01:00
For instance:
```
services.AddScoped<ISieveCustomSortMethods<Post>, SieveCustomSortMethodsOfPosts>();
services.AddScoped<ISieveCustomFilterMethods<Post>, SieveCustomFilterMethodsOfPosts>();
```
Where `SieveCustomSortMethodsOfPosts` for example is:
```
public class SieveCustomSortMethodsOfPosts : ISieveCustomSortMethods<Post>
{
2018-01-27 13:20:00 +01:00
public IQueryable<Post> Popularity(IQueryable<Post> source, bool useThenBy, bool desc) // The method is given an indicator of weather to use ThenBy(), and if the query is descending
2018-01-27 09:33:48 +01:00
{
var result = useThenBy ?
2018-01-28 00:54:13 +01:00
((IOrderedQueryable<Post>)source).ThenBy(p => p.LikeCount) : // ThenBy only works on IOrderedQueryable<TEntity>
2018-01-27 09:33:48 +01:00
source.OrderBy(p => p.LikeCount)
.ThenBy(p => p.CommentCount)
.ThenBy(p => p.DateCreated);
2018-01-27 13:20:00 +01:00
return result; // Must return modified IQueryable<TEntity>
2018-01-27 09:33:48 +01:00
}
}
```
And `SieveCustomFilterMethodsOfPosts`:
```
public class SieveCustomFilterMethodsOfPosts : ISieveCustomFilterMethods<Post>
{
2018-01-27 13:20:00 +01:00
public IQueryable<Post> IsNew(IQueryable<Post> source, string op, string value) // The method is given the {Operator} & {Value}
2018-01-27 09:33:48 +01:00
{
var result = source.Where(p => p.LikeCount < 100 &&
p.CommentCount < 5);
2018-01-27 13:20:00 +01:00
return result; // Must return modified IQueryable<TEntity>
2018-01-27 09:33:48 +01:00
}
}
```
2018-01-27 09:09:01 +01:00
2018-01-27 12:49:02 +01:00
### Configure Sieve
2018-01-27 09:33:48 +01:00
Use the [ASP.NET Core options pattern](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options) with `SieveOptions` to tell Sieve where to look for configuration. For example:
```
services.Configure<SieveOptions>(Configuration.GetSection("Sieve"));
```
2018-01-27 13:20:00 +01:00
Then you can add the configuration:
2018-01-27 12:49:02 +01:00
```
{
"Sieve": {
"CaseSensitive": `boolean: should property names be case-sensitive? Defaults to false`,
2018-01-27 13:20:00 +01:00
"DefaultPageSize": `number: optional number to fallback to when no page argument is given`
2018-01-27 12:49:02 +01:00
}
}
```
2018-01-27 09:09:01 +01:00
## Send a request
2018-01-28 00:54:13 +01:00
With all the above in place, you can now send a GET request that includes a sort/filter/page query.
2018-01-27 12:49:02 +01:00
An example:
2018-01-27 09:09:01 +01:00
```
GET /GetPosts
2018-01-27 12:49:02 +01:00
?sorts= LikeCount,CommentCount,-created // sort by likes, then comments, then descendingly by date created
&filters= LikeCount>10, Title@=awesome title, // filter to posts with more than 10 likes, and a title that contains the phrase "awesome title"
&page= 1 // get the first page...
&pageSize= 10 // ...which contains 10 posts
```
More formally:
* `sorts` is a comma-delimited ordered list of property names to sort by. Adding a `-` before the name switches to sorting descendingly.
* `filters` is a comma-delimited list of `{Name}{Operator}{Value}` where
* `{Name}` is the name of a property with the Sieve attribute or the name of a custom filter method for TEntity
2018-01-27 13:21:13 +01:00
* `{Operator}` is one of the [Operators](#operators) (has to be preceeded by a space when using custom filter methods)
* `{Value}` is the value to use for filtering
2018-01-27 12:49:02 +01:00
* `page` is the number of page to return
* `pageSize` is the number of items returned per page
Notes:
* Don't forget to remove commas from any `{Value}` fields
* You can have spaces anywhere except *within* `{Name}` or `{Operator}` fields
#### Creating your own DSL
You can replace this DSL with your own (eg. use JSON instead) by implementing an [ISieveModel](https://github.com/Biarity/Sieve/blob/master/Sieve/Models/ISieveModel.cs). You can use the default [SieveModel](https://github.com/Biarity/Sieve/blob/master/Sieve/Models/SieveModel.cs) for refrence.
### Operators
| Operator | Meaning |
|------------|--------------------------|
| `==` | Equals |
| `!=` | Not equals |
| `>` | Greater than |
| `<` | Less than |
| `>=` | Greater than or equal to |
| `<=` | Less than or equal to |
| `@=` | Contains |
| `_=` | Starts with |