Skip to content

Commit d6f76a4

Browse files
committed
merged main
2 parents e8efe45 + 32912d4 commit d6f76a4

2 files changed

Lines changed: 542 additions & 0 deletions

File tree

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
using System.Linq.Dynamic.Core;
2+
using System.Reflection;
3+
using System.Text;
4+
using System.Text.Json.Serialization;
5+
6+
public static class QueryableExtension
7+
{
8+
public static Dictionary<string, string> _filterOperations => new Dictionary<string, string>
9+
{
10+
{"eq", "=="},
11+
{"ne", "!="},
12+
{"contains", "Contains"},
13+
};
14+
15+
public static (IQueryable, int?) Apply<T>(this IQueryable<T> queryable, Query query, int? maxTop = null, ISearchBinder<T>? searchBinder = null)
16+
{
17+
var result = (IQueryable)queryable;
18+
19+
if (maxTop is not null && query.Top > maxTop)
20+
{
21+
throw new GoatQueryException("The value supplied for the query parameter 'Top' was greater than the maximum top allowed for this resource");
22+
}
23+
24+
// Filter
25+
if (!string.IsNullOrEmpty(query.Filter))
26+
{
27+
var filters = StringHelper.SplitString(query.Filter);
28+
29+
var where = new StringBuilder();
30+
31+
for (int i = 0; i < filters.Count; i++)
32+
{
33+
var filter = filters[i];
34+
var opts = StringHelper.SplitStringByWhitespace(filter.Trim());
35+
36+
if (opts.Count != 3)
37+
{
38+
continue;
39+
}
40+
41+
if (i > 0)
42+
{
43+
var prev = filters[i - 1];
44+
where.Append($" {prev.Trim()} ");
45+
}
46+
47+
var property = opts[0].Replace("\'", string.Empty);
48+
var operand = opts[1];
49+
var value = opts[2].Replace("'", "\"");
50+
51+
string? propertyName = typeof(T).GetProperties().FirstOrDefault(x => x.GetCustomAttribute<JsonPropertyNameAttribute>()?.Name == property)?.Name;
52+
53+
if (!string.IsNullOrEmpty(propertyName))
54+
{
55+
property = propertyName;
56+
}
57+
58+
if (typeof(T).GetProperties().FirstOrDefault(x => x.Name.Equals(property, StringComparison.OrdinalIgnoreCase))?.PropertyType == typeof(string))
59+
{
60+
if (operand.Equals("contains", StringComparison.OrdinalIgnoreCase))
61+
{
62+
where.Append($"{property}.ToLower().Contains({value}.ToLower())");
63+
}
64+
else
65+
{
66+
where.Append($"{property}.ToLower() {_filterOperations[operand]} {value}.ToLower()");
67+
}
68+
}
69+
else if (operand.Equals("contains", StringComparison.OrdinalIgnoreCase))
70+
{
71+
where.Append($"{property}.{_filterOperations[operand]}({value})");
72+
}
73+
else if (typeof(T).GetProperties().FirstOrDefault(x => x.Name.Equals(property, StringComparison.OrdinalIgnoreCase))?.PropertyType == typeof(Guid))
74+
{
75+
where.Append($"{property} {_filterOperations[operand]} Guid({value})");
76+
}
77+
else
78+
{
79+
where.Append($"{property} {_filterOperations[operand]} {value}");
80+
}
81+
}
82+
83+
result = result.Where(where.ToString());
84+
}
85+
86+
// Search
87+
if (searchBinder is not null && !string.IsNullOrEmpty(query.Search))
88+
{
89+
var searchExpression = searchBinder.Bind(query.Search);
90+
91+
if (searchExpression is null)
92+
{
93+
throw new GoatQueryException("search binder does not return valid expression that can be parsed to where clause");
94+
}
95+
96+
result = result.Where(searchExpression);
97+
}
98+
99+
int? count = null;
100+
101+
// Count
102+
if (query.Count ?? false)
103+
{
104+
count = result.Count();
105+
}
106+
107+
// Order by
108+
if (!string.IsNullOrEmpty(query.OrderBy))
109+
{
110+
result = result.OrderBy(query.OrderBy);
111+
}
112+
113+
// Select
114+
if (!string.IsNullOrEmpty(query.Select))
115+
{
116+
result = result.Select($"new {{ {query.Select} }}");
117+
}
118+
119+
// Skip
120+
if (query.Skip > 0)
121+
{
122+
result = result.Skip(query.Skip ?? 0);
123+
}
124+
125+
// Top
126+
if (query.Top > 0)
127+
{
128+
result = result.Take(query.Top ?? 0);
129+
}
130+
131+
return (result, count);
132+
}
133+
}

0 commit comments

Comments
 (0)