-
-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathSortParser.cs
More file actions
114 lines (94 loc) · 3.72 KB
/
Copy pathSortParser.cs
File metadata and controls
114 lines (94 loc) · 3.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
namespace QueryKit;
using System.Linq.Expressions;
using System.Reflection;
using Configuration;
using Exceptions;
using Sprache;
public static class SortParser
{
public class SortExpressionInfo<T>
{
public Expression<Func<T, object>>? Expression { get; set; }
public bool IsAscending { get; set; }
}
private const string Ascending = "asc";
private const string Descending = "desc";
internal static List<SortExpressionInfo<T>> ParseSort<T>(string input, IQueryKitConfiguration? config = null)
{
if(string.IsNullOrWhiteSpace(input))
return new List<SortExpressionInfo<T>>();
var sortClauses = input.Split(',');
var sortExpressions = new List<SortExpressionInfo<T>>();
foreach (var sortClause in sortClauses)
{
var sortExpression = CreateSortExpression<T>(sortClause.Trim(), config);
if (sortExpression.Expression != null)
{
sortExpressions.Add(sortExpression);
}
}
return sortExpressions;
}
private static SortExpressionInfo<T> CreateSortExpression<T>(string sortClause, IQueryKitConfiguration? config = null)
{
var parts = sortClause.Split();
var propertyName = parts[0];
var direction = parts.Length > 1 ? parts[1].ToLowerInvariant() : Ascending;
if (sortClause.StartsWith("-"))
{
direction = Descending;
propertyName = propertyName.Substring(1);
}
if (direction != Ascending && direction != Descending)
{
throw new ArgumentException($"Invalid direction: {direction}. Allowed values are '{Ascending}' and '{Descending}'.");
}
var propertyPath = config?.GetPropertyPathByQueryName(propertyName) ?? propertyName;
if (config != null && config.IsPropertySortable(propertyPath) == false)
{
return new SortExpressionInfo<T>
{
Expression = null,
IsAscending = true
};
}
var parameter = Expression.Parameter(typeof(T), "x");
var sortExpressionBody = CreateSortExpressionBody(parameter, propertyName, config);
if (sortExpressionBody == null)
{
return new SortExpressionInfo<T>
{
Expression = null,
IsAscending = true
};
}
var isAscending = direction == Ascending;
return new SortExpressionInfo<T>
{
Expression = Expression.Lambda<Func<T, object>>(Expression.Convert(sortExpressionBody, typeof(object)), parameter),
IsAscending = isAscending
};
}
private static Expression? CreateSortExpressionBody(Expression parameter, string propertyName, IQueryKitConfiguration? config)
{
var propertyPath = config?.GetPropertyPathByQueryName(propertyName) ?? propertyName;
var propertyNames = propertyPath.Split('.');
var propertyExpression = propertyNames.Aggregate(parameter, (expr, propName) =>
{
var propertyInfo = GetPropertyInfo(expr.Type, propName);
if (propertyInfo == null)
{
return null;
}
var actualPropertyName = propertyInfo?.Name ?? propName;
return Expression.PropertyOrField(expr, actualPropertyName);
});
if(propertyExpression == null)
throw new SortParsingException(propertyName);
return propertyExpression;
}
private static PropertyInfo? GetPropertyInfo(Type type, string propertyName)
{
return type.GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
}
}