mirror of
https://github.com/Biarity/Sieve.git
synced 2025-07-28 05:03:22 +02:00
SievePropertyMapper for #4
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
using System;
|
||||
using Sieve.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Sieve.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
|
||||
public class SieveAttribute : Attribute
|
||||
public class SieveAttribute : Attribute, ISievePropertyMetadata
|
||||
{
|
||||
/// <summary>
|
||||
/// Override name used
|
||||
|
14
Sieve/Models/ISievePropertyMetadata.cs
Normal file
14
Sieve/Models/ISievePropertyMetadata.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace Sieve.Models
|
||||
{
|
||||
public interface ISievePropertyMetadata
|
||||
{
|
||||
string Name { get; set; }
|
||||
bool CanFilter { get; set; }
|
||||
bool CanSort { get; set; }
|
||||
}
|
||||
}
|
14
Sieve/Models/SievePropertyMetadata.cs
Normal file
14
Sieve/Models/SievePropertyMetadata.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace Sieve.Models
|
||||
{
|
||||
public class SievePropertyMetadata : ISievePropertyMetadata
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public bool CanFilter { get; set; }
|
||||
public bool CanSort { get; set; }
|
||||
}
|
||||
}
|
@@ -19,12 +19,14 @@ namespace Sieve.Services
|
||||
private IOptions<SieveOptions> _options;
|
||||
private ISieveCustomSortMethods _customSortMethods;
|
||||
private ISieveCustomFilterMethods _customFilterMethods;
|
||||
private SievePropertyMapper mapper = new SievePropertyMapper();
|
||||
|
||||
|
||||
public SieveProcessor(IOptions<SieveOptions> options,
|
||||
ISieveCustomSortMethods customSortMethods,
|
||||
ISieveCustomFilterMethods customFilterMethods)
|
||||
{
|
||||
mapper = MapProperties(mapper);
|
||||
_options = options;
|
||||
_customSortMethods = customSortMethods;
|
||||
_customFilterMethods = customFilterMethods;
|
||||
@@ -33,6 +35,7 @@ namespace Sieve.Services
|
||||
public SieveProcessor(IOptions<SieveOptions> options,
|
||||
ISieveCustomSortMethods customSortMethods)
|
||||
{
|
||||
mapper = MapProperties(mapper);
|
||||
_options = options;
|
||||
_customSortMethods = customSortMethods;
|
||||
}
|
||||
@@ -40,12 +43,14 @@ namespace Sieve.Services
|
||||
public SieveProcessor(IOptions<SieveOptions> options,
|
||||
ISieveCustomFilterMethods customFilterMethods)
|
||||
{
|
||||
mapper = MapProperties(mapper);
|
||||
_options = options;
|
||||
_customFilterMethods = customFilterMethods;
|
||||
}
|
||||
|
||||
public SieveProcessor(IOptions<SieveOptions> options)
|
||||
{
|
||||
mapper = MapProperties(mapper);
|
||||
_options = options;
|
||||
}
|
||||
|
||||
@@ -57,7 +62,10 @@ namespace Sieve.Services
|
||||
/// <param name="source">Data source</param>
|
||||
/// <param name="dataForCustomMethods">Additional data that will be passed down to custom methods</param>
|
||||
/// <returns>Returns a transformed version of `source`</returns>
|
||||
public IQueryable<TEntity> ApplyAll<TEntity>(ISieveModel<IFilterTerm, ISortTerm> model, IQueryable<TEntity> source, object[] dataForCustomMethods = null)
|
||||
public IQueryable<TEntity> ApplyAll<TEntity>(
|
||||
ISieveModel<IFilterTerm, ISortTerm> model,
|
||||
IQueryable<TEntity> source,
|
||||
object[] dataForCustomMethods = null)
|
||||
{
|
||||
var result = source;
|
||||
|
||||
@@ -84,7 +92,10 @@ namespace Sieve.Services
|
||||
/// <param name="source">Data source</param>
|
||||
/// <param name="dataForCustomMethods">Additional data that will be passed down to custom methods</param>
|
||||
/// <returns>Returns a transformed version of `source`</returns>
|
||||
public IQueryable<TEntity> ApplyFiltering<TEntity>(ISieveModel<IFilterTerm, ISortTerm> model, IQueryable<TEntity> result, object[] dataForCustomMethods = null)
|
||||
public IQueryable<TEntity> ApplyFiltering<TEntity>(
|
||||
ISieveModel<IFilterTerm, ISortTerm> model,
|
||||
IQueryable<TEntity> result,
|
||||
object[] dataForCustomMethods = null)
|
||||
{
|
||||
if (model?.FiltersParsed == null)
|
||||
return result;
|
||||
@@ -181,7 +192,10 @@ namespace Sieve.Services
|
||||
/// <param name="source">Data source</param>
|
||||
/// <param name="dataForCustomMethods">Additional data that will be passed down to custom methods</param>
|
||||
/// <returns>Returns a transformed version of `source`</returns>
|
||||
public IQueryable<TEntity> ApplySorting<TEntity>(ISieveModel<IFilterTerm, ISortTerm> model, IQueryable<TEntity> result, object[] dataForCustomMethods = null)
|
||||
public IQueryable<TEntity> ApplySorting<TEntity>(
|
||||
ISieveModel<IFilterTerm, ISortTerm> model,
|
||||
IQueryable<TEntity> result,
|
||||
object[] dataForCustomMethods = null)
|
||||
{
|
||||
if (model?.SortsParsed == null)
|
||||
return result;
|
||||
@@ -219,7 +233,9 @@ namespace Sieve.Services
|
||||
/// <param name="source">Data source</param>
|
||||
/// <param name="dataForCustomMethods">Additional data that will be passed down to custom methods</param>
|
||||
/// <returns>Returns a transformed version of `source`</returns>
|
||||
public IQueryable<TEntity> ApplyPagination<TEntity>(ISieveModel<IFilterTerm, ISortTerm> model, IQueryable<TEntity> result)
|
||||
public IQueryable<TEntity> ApplyPagination<TEntity>(
|
||||
ISieveModel<IFilterTerm, ISortTerm> model,
|
||||
IQueryable<TEntity> result)
|
||||
{
|
||||
var page = model?.Page ?? 1;
|
||||
var pageSize = model?.PageSize ?? _options.Value.DefaultPageSize;
|
||||
@@ -232,15 +248,34 @@ namespace Sieve.Services
|
||||
return result;
|
||||
}
|
||||
|
||||
private PropertyInfo GetSieveProperty<TEntity>(bool canSortRequired, bool canFilterRequired, string name)
|
||||
|
||||
protected virtual SievePropertyMapper MapProperties(SievePropertyMapper mapper)
|
||||
{
|
||||
return mapper;
|
||||
}
|
||||
|
||||
private PropertyInfo GetSieveProperty<TEntity>(
|
||||
bool canSortRequired,
|
||||
bool canFilterRequired,
|
||||
string name)
|
||||
{
|
||||
return mapper.FindProperty<TEntity>(canSortRequired, canFilterRequired, name, _options.Value.CaseSensitive)
|
||||
?? FindPropertyBySieveAttribute<TEntity>(canSortRequired, canFilterRequired, name, _options.Value.CaseSensitive);
|
||||
}
|
||||
|
||||
private PropertyInfo FindPropertyBySieveAttribute<TEntity>(
|
||||
bool canSortRequired,
|
||||
bool canFilterRequired,
|
||||
string name,
|
||||
bool isCaseSensitive)
|
||||
{
|
||||
return typeof(TEntity).GetProperties().FirstOrDefault(p =>
|
||||
{
|
||||
if (p.GetCustomAttribute(typeof(SieveAttribute)) is SieveAttribute sieveAttribute)
|
||||
if ((canSortRequired ? sieveAttribute.CanSort : true) &&
|
||||
(canFilterRequired ? sieveAttribute.CanFilter : true) &&
|
||||
((sieveAttribute.Name ?? p.Name).Equals(name,
|
||||
_options.Value.CaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase)))
|
||||
((sieveAttribute.Name ?? p.Name).Equals(name,
|
||||
isCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase)))
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
|
107
Sieve/Services/SievePropertyMapper.cs
Normal file
107
Sieve/Services/SievePropertyMapper.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
using Sieve.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace Sieve.Services
|
||||
{
|
||||
public class SievePropertyMapper
|
||||
{
|
||||
private Dictionary<Type, Dictionary<PropertyInfo, ISievePropertyMetadata>> _map
|
||||
= new Dictionary<Type, Dictionary<PropertyInfo, ISievePropertyMetadata>>();
|
||||
|
||||
public PropertyFluentApi<TEntity> Property<TEntity>(Expression<Func<TEntity, object>> expression)
|
||||
{
|
||||
_map.TryAdd(typeof(TEntity), new Dictionary<PropertyInfo, ISievePropertyMetadata>());
|
||||
return new PropertyFluentApi<TEntity>(this, expression);
|
||||
}
|
||||
|
||||
public class PropertyFluentApi<TEntity>
|
||||
{
|
||||
private SievePropertyMapper _sievePropertyMapper;
|
||||
private PropertyInfo _property;
|
||||
|
||||
public PropertyFluentApi(SievePropertyMapper sievePropertyMapper, Expression<Func<TEntity, object>> expression)
|
||||
{
|
||||
_sievePropertyMapper = sievePropertyMapper;
|
||||
_property = GetPropertyInfo(expression);
|
||||
_name = _property.Name;
|
||||
_canFilter = false;
|
||||
_canSort = false;
|
||||
}
|
||||
|
||||
private string _name;
|
||||
private bool _canFilter;
|
||||
private bool _canSort;
|
||||
|
||||
public PropertyFluentApi<TEntity> CanFilter()
|
||||
{
|
||||
_canFilter = true;
|
||||
UpdateMap();
|
||||
return this;
|
||||
}
|
||||
|
||||
public PropertyFluentApi<TEntity> CanSort()
|
||||
{
|
||||
_canSort = true;
|
||||
UpdateMap();
|
||||
return this;
|
||||
}
|
||||
|
||||
public PropertyFluentApi<TEntity> HasName(string name)
|
||||
{
|
||||
_name = name;
|
||||
UpdateMap();
|
||||
return this;
|
||||
}
|
||||
|
||||
private void UpdateMap()
|
||||
{
|
||||
_sievePropertyMapper._map[typeof(TEntity)][_property] = new SievePropertyMetadata()
|
||||
{
|
||||
Name = _name,
|
||||
CanFilter = _canFilter,
|
||||
CanSort = _canSort
|
||||
};
|
||||
}
|
||||
|
||||
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 FindProperty<TEntity>(
|
||||
bool canSortRequired,
|
||||
bool canFilterRequired,
|
||||
string name,
|
||||
bool isCaseSensitive)
|
||||
{
|
||||
try
|
||||
{
|
||||
var me = _map[typeof(TEntity)]
|
||||
.FirstOrDefault(kv =>
|
||||
kv.Value.Name.Equals(name, isCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase) &&
|
||||
(canSortRequired ? kv.Value.CanSort : true) &&
|
||||
(canFilterRequired ? kv.Value.CanFilter : true));
|
||||
|
||||
return me.Key;
|
||||
}
|
||||
catch (Exception ex) when (ex is KeyNotFoundException || ex is ArgumentNullException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user