Skip to content

Commit 459508d

Browse files
(feature) Parser.AddCustomFilter added to perform extra filters on IQueryable maintaining total count
1 parent de8ad4f commit 459508d

File tree

2 files changed

+45
-6
lines changed

2 files changed

+45
-6
lines changed

src/DatatablesParser/DatatablesParser.cs

+22-6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace DataTablesParser
1010
{
1111
public class Parser<T> where T : class
1212
{
13+
private IQueryable<T> _originalQuery;
1314
private IQueryable<T> _query;
1415
private readonly Dictionary<string,string> _config;
1516
private readonly Type _type;
@@ -42,6 +43,7 @@ public class Parser<T> where T : class
4243

4344
public Parser(IEnumerable<KeyValuePair<string, StringValues>> configParams, IQueryable<T> query)
4445
{
46+
_originalQuery = query;
4547
_query = query;
4648
_config = configParams.ToDictionary(k => k.Key,v=> v.Value.First().Trim());
4749
_type = typeof(T);
@@ -104,7 +106,7 @@ public Results<T> Parse()
104106
list.draw = int.Parse(_config[Constants.DRAW]);
105107

106108
// count the record BEFORE filtering
107-
list.recordsTotal = _query.Count();
109+
list.recordsTotal = _originalQuery.Count();
108110

109111
//sort results if sorting isn't disabled or skip needs to be called
110112
if(!_sortDisabled || _skip > 0)
@@ -124,16 +126,19 @@ public Results<T> Parse()
124126
resultQuery = _query.Where(entityFilter)
125127
.Skip(_skip)
126128
.Take(_take);
127-
128-
list.recordsFiltered = _query.Count(entityFilter);
129+
130+
list.recordsFiltered = _query.Count(entityFilter);
129131
}
130132
else
131133
{
132134
resultQuery = _query
133135
.Skip(_skip)
134136
.Take(_take);
135-
136-
list.recordsFiltered = list.recordsTotal;
137+
138+
if(_query == _originalQuery)
139+
list.recordsFiltered = list.recordsTotal;
140+
else
141+
list.recordsFiltered = _query.Count();
137142

138143
}
139144

@@ -191,6 +196,17 @@ public Parser<T> SetEndsWithToken(string token)
191196
return this;
192197
}
193198

199+
/// <summary>
200+
/// AddCustomFilter add external custom filter to handle complex filtering logic
201+
/// For example date range filtering
202+
/// </summary>
203+
/// <param name="predicate">Filter logic</param>
204+
/// <returns></returns>
205+
public Parser<T> AddCustomFilter(Expression<Func<T, bool>> predicate)
206+
{
207+
_query = _query.Where(predicate);
208+
return this;
209+
}
194210

195211
private void ApplySort()
196212
{
@@ -359,7 +375,7 @@ private Expression<Func<T, bool>> GenerateEntityFilter()
359375

360376
if(globalFilterConst!=null)
361377
{
362-
var globalTest = Expression.Call(toLower, typeof(string).GetMethod(globalFilterFn, new[] { typeof(string) }), globalFilterConst);
378+
Expression globalTest = Expression.Call(toLower, typeof(string).GetMethod(globalFilterFn, new[] { typeof(string) }), globalFilterConst);
363379

364380
if(filterExpr == null)
365381
{

test/DatatablesParser.Tests/MysqlEntityTests.cs

+23
Original file line numberDiff line numberDiff line change
@@ -127,5 +127,28 @@ public void ResultsWhenSearchInNullColumnTest()
127127

128128
}
129129

130+
[Fact]
131+
public void AddCustomFilterTest()
132+
{
133+
var context = TestHelper.GetMysqlContext();
134+
var p = TestHelper.CreateParams();
135+
var displayLength = 2; // James and Tony
136+
137+
138+
var parser = new Parser<Person>(p, context.People); // p is empty, all rows
139+
140+
var minDate = DateTime.Parse("1960-01-01");
141+
var maxDate = DateTime.Parse("1970-01-01");
142+
parser.AddCustomFilter(x => x.BirthDate >= minDate);
143+
parser.AddCustomFilter(x => x.BirthDate < maxDate);
144+
145+
var result = parser.Parse().recordsFiltered;
146+
147+
Console.WriteLine("MySql - Search only born between 1960 and 1970: {0}", result);
148+
149+
Assert.Equal(displayLength, result);
150+
151+
}
152+
130153
}
131154
}

0 commit comments

Comments
 (0)