Skip to content

Enum Support & Nested Sort / Filter #35

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion PrimeNG.TableFilter.Test/PrimeNG.TableFilter.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
</ItemGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions PrimeNG.TableFilter/Core/ITableFilterManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public interface ITableFilterManager<out TEntity>
void MultipleOrderDataSet(TableFilterModel tableFilterPayload);
void SingleOrderDataSet(TableFilterModel tableFilterPayload);
void FilterDataSet(string key, TableFilterContext value);
void FilterDataSet(string key, TableFilterContext value, OperatorEnumeration opMode);
void FiltersDataSet(string key, IEnumerable<TableFilterContext> values);
void ExecuteFilter();
IQueryable<TEntity> GetResult();
Expand Down
100 changes: 88 additions & 12 deletions PrimeNG.TableFilter/Core/LinqOperator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,64 @@ public void AddFilterProperty(
OperatorEnumeration operatorAction,
bool isNegation = false)
{
var property = _context.DataSetType.GetProperty(propertyName);
PropertyInfo property = null;
foreach (var item in propertyName.Split('.'))
{
if (property == null)
property = _context.DataSetType.GetProperty(item.FirstCharToUpper());
else
property = property.PropertyType.GetProperty(item.FirstCharToUpper());
}
var propertyType = property?.PropertyType;

if (propertyType == null)
return;

if (!IsPropertyTypeAndFilterMatchModeValid(propertyType, extensionMethod))
if (propertyType != typeof(string) && extensionMethod == LinqOperatorConstants.ConstantContains)
{
if (propertyType == typeof(DateTime) || propertyType == typeof(DateTime?))
{
extensionMethod = LinqOperatorConstants.ConstantDateIs;
if (DateTime.TryParse(propertyValue.ToString(), out var currentDate))
propertyValue = currentDate;
else
return;
}
else if (propertyType == typeof(bool) || propertyType == typeof(bool?))
{
extensionMethod = LinqOperatorConstants.ConstantEquals;
if (bool.TryParse(propertyValue.ToString(),out var currentBoolean))
propertyValue = currentBoolean;
else
return;
}
else if (IsNumericType(propertyType))
{
extensionMethod = LinqOperatorConstants.ConstantEquals;
if ((propertyType == typeof(short) || propertyType == typeof(short?)) && short.TryParse(propertyValue.ToString(), out var currentShort))
propertyValue = currentShort;
else if ((propertyType == typeof(int) || propertyType == typeof(int?)) && int.TryParse(propertyValue.ToString(), out var currentInt))
propertyValue = currentInt;
else if ((propertyType == typeof(long) || propertyType == typeof(long?)) && long.TryParse(propertyValue.ToString(), out var currentLong))
propertyValue = currentLong;
else if ((propertyType == typeof(float) || propertyType == typeof(float?)) && float.TryParse(propertyValue.ToString(), out var currentFloat))
propertyValue = currentFloat;
else if ((propertyType == typeof(double) || propertyType == typeof(double?)) && double.TryParse(propertyValue.ToString(), out var currentDouble))
propertyValue = currentDouble;
else if ((propertyType == typeof(decimal) || propertyType == typeof(decimal?)) && decimal.TryParse(propertyValue.ToString(), out var currentDecimal))
propertyValue = currentDecimal;
else if ((propertyType.IsEnum || (Nullable.GetUnderlyingType(propertyType)?.IsEnum == true)) && int.TryParse(propertyValue.ToString(), out var currentEnum))
propertyValue = currentEnum;
else
return;
}
}

if (!IsPropertyTypeAndFilterMatchModeValid(propertyType, extensionMethod))
throw new ArgumentException($"Property ${propertyName} not support method ${extensionMethod}");

var castValue = ObjectCasterUtil.CastPropertiesType(property, propertyValue);
var propertyConstant = Expression.Constant(castValue, propertyType);
var propertyConstant = propertyType.IsEnum ? Expression.Constant(castValue, typeof(int)) : Expression.Constant(castValue, propertyType);

if (IsNullableType(propertyType))
{
Expand Down Expand Up @@ -90,8 +137,14 @@ public void AddFilterProperty(
return;
case string _:
{
var propertyAccess = Expression.MakeMemberAccess(_context.ParameterExpression,
property ?? throw new InvalidOperationException());
MemberExpression propertyAccess = null;
foreach (var item in propertyName.Split('.'))
{
if (propertyAccess == null)
propertyAccess = Expression.PropertyOrField(_context.ParameterExpression, item.FirstCharToUpper());
else
propertyAccess = Expression.PropertyOrField(propertyAccess, item.FirstCharToUpper());
}

var methodInfo = propertyType.GetMethod(extensionMethod, new[] { propertyType });
if (isNegation)
Expand Down Expand Up @@ -193,13 +246,31 @@ public void ThenByDescending(string orderProperty) =>

private void BaseOrderExecute(string command, string orderByProperty)
{
var property = _context.DataSetType.GetProperty(orderByProperty);
var propertyAccess =
Expression.MakeMemberAccess(_context.ParameterExpression,
property ?? throw new InvalidOperationException());
PropertyInfo property = null;
foreach (var item in orderByProperty.Split('.'))
{
if (property == null)
property = _context.DataSetType.GetProperty(item.FirstCharToUpper());
else
property = property.PropertyType.GetProperty(item.FirstCharToUpper());
}
var propertyType = property?.PropertyType;

if (propertyType == null)
return;

MemberExpression propertyAccess = null;
foreach (var item in orderByProperty.Split('.'))
{
if (propertyAccess == null)
propertyAccess = Expression.PropertyOrField(_context.ParameterExpression, item);
else
propertyAccess = Expression.PropertyOrField(propertyAccess, item);
}

var orderByExpression = Expression.Lambda(propertyAccess, _context.ParameterExpression);
var resultExpression = Expression.Call(typeof(Queryable), command,
new[] { _context.DataSetType, property.PropertyType },
new[] { _context.DataSetType, propertyType },
_context.DataSet.Expression, Expression.Quote(orderByExpression));
_context.DataSet = _context.DataSet.Provider.CreateQuery<TEntity>(resultExpression);
}
Expand All @@ -220,8 +291,13 @@ private static bool IsNullableType(Type propertyType)
/// <returns><code>True</code> if nullable, otherwise <code>False</code></returns>
private static bool IsNumericType(Type propertyType)
{
return (propertyType == typeof(short) || propertyType == typeof(short?) || propertyType == typeof(int) || propertyType == typeof(int?) || propertyType == typeof(long) || propertyType == typeof(long?)
|| propertyType == typeof(float) || propertyType == typeof(float?) || propertyType == typeof(double) || propertyType == typeof(double?) || propertyType == typeof(decimal) || propertyType == typeof(decimal?));
return ((propertyType == typeof(short) || propertyType == typeof(short?)) ||
(propertyType == typeof(int) || propertyType == typeof(int?)) ||
(propertyType == typeof(long) || propertyType == typeof(long?)) ||
(propertyType == typeof(float) || propertyType == typeof(float?)) ||
(propertyType == typeof(double) || propertyType == typeof(double?)) ||
(propertyType == typeof(decimal) || propertyType == typeof(decimal?)) ||
(propertyType.IsEnum || (Nullable.GetUnderlyingType(propertyType)?.IsEnum == true)));
}
/// <summary>
/// Checks if for provided <paramref name="propertyType"/>, <paramref name="extensionMethod"/> is valid
Expand Down
53 changes: 30 additions & 23 deletions PrimeNG.TableFilter/Core/TableFilterManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,16 @@ public void MultipleOrderDataSet(TableFilterModel tableFilterPayload)
{
case (int)SortingEnumeration.OrderByAsc:
if (o.i == 0)
_linqOperator.OrderBy(o.value.Field.FirstCharToUpper());
_linqOperator.OrderBy(o.value.Field);
else
_linqOperator.ThenBy(o.value.Field.FirstCharToUpper());
_linqOperator.ThenBy(o.value.Field);
break;

case (int)SortingEnumeration.OrderByDesc:
if (o.i == 0)
_linqOperator.OrderByDescending(o.value.Field.FirstCharToUpper());
_linqOperator.OrderByDescending(o.value.Field);
else
_linqOperator.ThenByDescending(o.value.Field.FirstCharToUpper());
_linqOperator.ThenByDescending(o.value.Field);
break;

default:
Expand All @@ -77,11 +77,11 @@ public void SingleOrderDataSet(TableFilterModel tableFilterPayload)
switch (tableFilterPayload.SortOrder)
{
case (int)SortingEnumeration.OrderByAsc:
_linqOperator.OrderBy(tableFilterPayload.SortField.FirstCharToUpper());
_linqOperator.OrderBy(tableFilterPayload.SortField);
break;

case (int)SortingEnumeration.OrderByDesc:
_linqOperator.OrderByDescending(tableFilterPayload.SortField.FirstCharToUpper());
_linqOperator.OrderByDescending(tableFilterPayload.SortField);
break;

default:
Expand All @@ -97,6 +97,15 @@ public void SingleOrderDataSet(TableFilterModel tableFilterPayload)
public void FilterDataSet(string key, TableFilterContext value)
=> BaseFilterDataSet(key, value, OperatorEnumeration.None);

/// <summary>
/// Set filter condition data to LINQ Operation context
/// </summary>
/// <param name="key">Name of property</param>
/// <param name="value">PrimeNG filter context</param>
/// <param name="filterOperator">PrimeNG filter connection operator</param>
public void FilterDataSet(string key, TableFilterContext value, OperatorEnumeration filterOperator)
=> BaseFilterDataSet(key, value, filterOperator);

/// <summary>
/// The base method for set filter condition data to LINQ Operation context
/// </summary>
Expand All @@ -112,87 +121,85 @@ private void BaseFilterDataSet(string key, TableFilterContext value, OperatorEnu
switch (value.MatchMode)
{
case ConstantTypeMatchModeStartsWith:
_linqOperator.AddFilterProperty(key.FirstCharToUpper(), value.Value,
_linqOperator.AddFilterProperty(key, value.Value,
LinqOperatorConstants.ConstantStartsWith
, operatorAction);
break;

case ConstantTypeMatchModeContains:
_linqOperator.AddFilterProperty(key.FirstCharToUpper(), value.Value,
_linqOperator.AddFilterProperty(key, value.Value,
LinqOperatorConstants.ConstantContains
, operatorAction);
break;

case ConstantTypeMatchModeIn:
_linqOperator.AddFilterListProperty(key.FirstCharToUpper(), value.Value
_linqOperator.AddFilterListProperty(key, value.Value
, operatorAction);
break;

case ConstantTypeMatchModeEndsWith:
_linqOperator.AddFilterProperty(key.FirstCharToUpper(), value.Value,
_linqOperator.AddFilterProperty(key, value.Value,
LinqOperatorConstants.ConstantEndsWith
, OperatorEnumeration.None);
break;

case ConstantTypeMatchModeEquals:
_linqOperator.AddFilterProperty(key.FirstCharToUpper(), value.Value,
_linqOperator.AddFilterProperty(key, value.Value,
LinqOperatorConstants.ConstantEquals
, operatorAction);
break;

case ConstantTypeMatchModeNotContains:
_linqOperator.AddFilterProperty(key.FirstCharToUpper(), value.Value,
_linqOperator.AddFilterProperty(key, value.Value,
LinqOperatorConstants.ConstantContains
, OperatorEnumeration.None, true);
break;

case ConstantTypeMatchModeNotEquals:
_linqOperator.AddFilterProperty(key.FirstCharToUpper(), value.Value,
_linqOperator.AddFilterProperty(key, value.Value,
LinqOperatorConstants.ConstantEquals
, operatorAction, true);
break;
case ConstantTypeMatchModeDateIs:
_linqOperator.AddFilterProperty(key.FirstCharToUpper(), value.Value,
_linqOperator.AddFilterProperty(key, value.Value,
LinqOperatorConstants.ConstantDateIs
, operatorAction);
break;
case ConstantTypeMatchModeDateIsNot:
_linqOperator.AddFilterProperty(key.FirstCharToUpper(), value.Value,
_linqOperator.AddFilterProperty(key, value.Value,
LinqOperatorConstants.ConstantDateIs
, operatorAction, true);
break;
case ConstantTypeMatchModeDateBefore:
_linqOperator.AddFilterProperty(key.FirstCharToUpper(), value.Value,
_linqOperator.AddFilterProperty(key, value.Value,
LinqOperatorConstants.ConstantBefore
, operatorAction);
break;
case ConstantTypeMatchModeDateAfter:
_linqOperator.AddFilterProperty(key.FirstCharToUpper(), value.Value,
_linqOperator.AddFilterProperty(key, value.Value,
LinqOperatorConstants.ConstantAfter
, operatorAction);
break;
case ConstantTypeMatchModeLessThan:
_linqOperator.AddFilterProperty(key.FirstCharToUpper(), value.Value,
_linqOperator.AddFilterProperty(key, value.Value,
LinqOperatorConstants.ConstantLessThan
, operatorAction);
break;
case ConstantTypeMatchModeLessOrEqualsThan:
_linqOperator.AddFilterProperty(key.FirstCharToUpper(), value.Value,
_linqOperator.AddFilterProperty(key, value.Value,
LinqOperatorConstants.ConstantLessThanOrEqual
, operatorAction);
break;
case ConstantTypeMatchModeGreaterThan:
_linqOperator.AddFilterProperty(key.FirstCharToUpper(), value.Value,
_linqOperator.AddFilterProperty(key, value.Value,
LinqOperatorConstants.ConstantGreaterThan
, operatorAction);
break;
case ConstantTypeMatchModeGreaterOrEqualsThan:
_linqOperator.AddFilterProperty(key.FirstCharToUpper(), value.Value,
_linqOperator.AddFilterProperty(key, value.Value,
LinqOperatorConstants.ConstantGreaterThanOrEqual
, operatorAction);
break;


default:
throw new System.ArgumentException("Invalid Match mode!");
}
Expand Down
8 changes: 4 additions & 4 deletions PrimeNG.TableFilter/Models/TableFilterModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ namespace PrimeNG.TableFilter.Models
{
public class TableFilterModel
{
public Dictionary<string, object> Filters { get; set; }
public int First { get; set; }
public int Rows { get; set; }
public Dictionary<string, object> Filters { get; set; } = new Dictionary<string, object>();
public int First { get; set; } = 0;
public int Rows { get; set; } = 10;
public string SortField { get; set; }
public int SortOrder { get; set; }
public List<TableFilterSortMeta> MultiSortMeta { get; set; }
public List<TableFilterSortMeta> MultiSortMeta { get; set; } = new List<TableFilterSortMeta>();
}
}
6 changes: 3 additions & 3 deletions PrimeNG.TableFilter/PrimeNG.TableFilter.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<RepositoryUrl>https://github.com/Kusumoto/PrimeNG.TableFilter</RepositoryUrl>
<Version>2.1.2</Version>
<PackageVersion>2.1.2</PackageVersion>
<TargetFrameworks>net462;netstandard2.1;net6.0;net5.0</TargetFrameworks>
<TargetFrameworks>net462;netstandard2.1;net6.0;net5.0;net7.0</TargetFrameworks>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
<AssemblyVersion>2.1.2</AssemblyVersion>
Expand All @@ -21,8 +21,8 @@
<Folder Include="Utils\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.13" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.25" />
</ItemGroup>
<ItemGroup>
<None Include="..\LICENSE.md">
Expand Down
Loading