Extended SieveProcessor to optionally accept a list of SieveProperties.

This commit is contained in:
Thomas Flanitzer 2018-02-09 09:12:34 +01:00
parent aa6a836cfb
commit c9014a913c
5 changed files with 99 additions and 13 deletions

12
Sieve/Models/Allow.cs Normal file
View File

@ -0,0 +1,12 @@
using System;
namespace Sieve.Models
{
[Flags]
public enum Allow
{
Sort = 1,
Filter = 2,
SortAndFilter = 4
}
}

View File

@ -0,0 +1,43 @@
using System;
using System.Linq.Expressions;
using System.Reflection;
namespace Sieve.Models
{
public class SieveProperty<TEntity>
{
public static SieveProperty<TEntity> For(Expression<Func<TEntity, object>> expression, Allow allow, string nameInQuery = null)
{
var propertyInfo = GetPropertyInfo(expression);
if (nameInQuery == null)
nameInQuery = propertyInfo.Name;
return new SieveProperty<TEntity>(propertyInfo, nameInQuery, allow.HasFlag(Allow.Sort), allow.HasFlag(Allow.Filter));
}
private static PropertyInfo GetPropertyInfo(Expression<Func<TEntity, object>> exp)
{
if (!(exp.Body is MemberExpression body))
{
var ubody = (UnaryExpression) exp.Body;
body = ubody.Operand as MemberExpression;
}
return body?.Member as PropertyInfo;
}
public PropertyInfo PropertyInfo { get; }
public string NameInQuery { get; }
public bool CanSort { get; }
public bool CanFilter { get; }
public SieveProperty(PropertyInfo propertyInfo, string nameInQuery, bool canSort, bool canFilter)
{
PropertyInfo = propertyInfo;
NameInQuery = nameInQuery;
CanSort = canSort;
CanFilter = canFilter;
}
}
}

View File

@ -6,9 +6,9 @@ namespace Sieve.Services
{ {
public interface ISieveProcessor public interface ISieveProcessor
{ {
IQueryable<TEntity> ApplyAll<TEntity>(ISieveModel model, IQueryable<TEntity> source, object[] dataForCustomMethods = null); IQueryable<TEntity> ApplyAll<TEntity>(ISieveModel model, IQueryable<TEntity> source, SieveProperty<TEntity>[] sieveProperties = null, object[] dataForCustomMethods = null);
IQueryable<TEntity> ApplySorting<TEntity>(ISieveModel model, IQueryable<TEntity> result, object[] dataForCustomMethods = null); IQueryable<TEntity> ApplySorting<TEntity>(ISieveModel model, IQueryable<TEntity> result, SieveProperty<TEntity>[] sieveProperties = null, object[] dataForCustomMethods = null);
IQueryable<TEntity> ApplyFiltering<TEntity>(ISieveModel model, IQueryable<TEntity> result, object[] dataForCustomMethods = null); IQueryable<TEntity> ApplyFiltering<TEntity>(ISieveModel model, IQueryable<TEntity> result, SieveProperty<TEntity>[] sieveProperties = null, object[] dataForCustomMethods = null);
IQueryable<TEntity> ApplyPagination<TEntity>(ISieveModel model, IQueryable<TEntity> result); IQueryable<TEntity> ApplyPagination<TEntity>(ISieveModel model, IQueryable<TEntity> result);
} }
} }

View File

@ -20,7 +20,6 @@ namespace Sieve.Services
private ISieveCustomSortMethods _customSortMethods; private ISieveCustomSortMethods _customSortMethods;
private ISieveCustomFilterMethods _customFilterMethods; private ISieveCustomFilterMethods _customFilterMethods;
public SieveProcessor(IOptions<SieveOptions> options, public SieveProcessor(IOptions<SieveOptions> options,
ISieveCustomSortMethods customSortMethods, ISieveCustomSortMethods customSortMethods,
ISieveCustomFilterMethods customFilterMethods) ISieveCustomFilterMethods customFilterMethods)
@ -49,7 +48,11 @@ namespace Sieve.Services
_options = options; _options = options;
} }
public IQueryable<TEntity> ApplyAll<TEntity>(ISieveModel model, IQueryable<TEntity> source, object[] dataForCustomMethods = null) public IQueryable<TEntity> ApplyAll<TEntity>(
ISieveModel model,
IQueryable<TEntity> source,
SieveProperty<TEntity>[] sieveProperties = null,
object[] dataForCustomMethods = null)
{ {
var result = source; var result = source;
@ -57,10 +60,10 @@ namespace Sieve.Services
return result; return result;
// Filter // Filter
result = ApplyFiltering(model, result, dataForCustomMethods); result = ApplyFiltering(model, result, sieveProperties, dataForCustomMethods);
// Sort // Sort
result = ApplySorting(model, result, dataForCustomMethods); result = ApplySorting(model, result, sieveProperties, dataForCustomMethods);
// Paginate // Paginate
result = ApplyPagination(model, result); result = ApplyPagination(model, result);
@ -68,7 +71,11 @@ namespace Sieve.Services
return result; return result;
} }
public IQueryable<TEntity> ApplySorting<TEntity>(ISieveModel model, IQueryable<TEntity> result, object[] dataForCustomMethods = null) public IQueryable<TEntity> ApplySorting<TEntity>(
ISieveModel model,
IQueryable<TEntity> result,
SieveProperty<TEntity>[] sieveProperties = null,
object[] dataForCustomMethods = null)
{ {
if (model?.SortsParsed == null) if (model?.SortsParsed == null)
return result; return result;
@ -76,7 +83,8 @@ namespace Sieve.Services
var useThenBy = false; var useThenBy = false;
foreach (var sortTerm in model.SortsParsed) foreach (var sortTerm in model.SortsParsed)
{ {
var property = GetSieveProperty<TEntity>(true, false, sortTerm.Name); var property = sieveProperties?.FirstOrDefault(_ => _.NameInQuery == sortTerm.Name && _.CanSort)?.PropertyInfo
?? GetSievePropertyViaAttribute<TEntity>(true, false, sortTerm.Name);
if (property != null) if (property != null)
{ {
@ -98,14 +106,19 @@ namespace Sieve.Services
return result; return result;
} }
public IQueryable<TEntity> ApplyFiltering<TEntity>(ISieveModel model, IQueryable<TEntity> result, object[] dataForCustomMethods = null) public IQueryable<TEntity> ApplyFiltering<TEntity>(
ISieveModel model,
IQueryable<TEntity> result,
SieveProperty<TEntity>[] sieveProperties = null,
object[] dataForCustomMethods = null)
{ {
if (model?.FiltersParsed == null) if (model?.FiltersParsed == null)
return result; return result;
foreach (var filterTerm in model.FiltersParsed) foreach (var filterTerm in model.FiltersParsed)
{ {
var property = GetSieveProperty<TEntity>(false, true, filterTerm.Name); var property = sieveProperties?.FirstOrDefault(_ => _.NameInQuery == filterTerm.Name && _.CanFilter)?.PropertyInfo
?? GetSievePropertyViaAttribute<TEntity>(false, true, filterTerm.Name);
if (property != null) if (property != null)
{ {
@ -188,7 +201,7 @@ namespace Sieve.Services
return result; return result;
} }
private PropertyInfo GetSieveProperty<TEntity>(bool canSortRequired, bool canFilterRequired, string name) private PropertyInfo GetSievePropertyViaAttribute<TEntity>(bool canSortRequired, bool canFilterRequired, string name)
{ {
return typeof(TEntity).GetProperties().FirstOrDefault(p => return typeof(TEntity).GetProperties().FirstOrDefault(p =>
{ {

View File

@ -33,6 +33,24 @@ namespace SieveTests.Controllers
return Json(result.ToList()); return Json(result.ToList());
} }
[HttpGet]
public JsonResult GetAllWithSieveAndPropertyMapping(SieveModel sieveModel)
{
var result = _dbContext.Posts.AsNoTracking();
var sieveProperties = new[]
{
SieveProperty<Post>.For(_ => _.Title, Allow.Filter, "name"),
SieveProperty<Post>.For(_ => _.CommentCount, Allow.SortAndFilter),
SieveProperty<Post>.For(_ => _.LikeCount, Allow.Sort),
SieveProperty<Post>.For(_ => _.DateCreated, Allow.SortAndFilter),
};
result = _sieveProcessor.ApplyAll(sieveModel, result, sieveProperties);
return Json(result.ToList());
}
[HttpGet] [HttpGet]
public JsonResult Create(int number = 10) public JsonResult Create(int number = 10)
{ {