2018-10-18 21:52:05 -04:00
|
|
|
|
using System;
|
2018-10-17 22:14:21 -04:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
using System.Text;
|
2018-10-18 21:52:05 -04:00
|
|
|
|
using PoweredSoft.DynamicLinq;
|
2018-10-21 14:15:21 -04:00
|
|
|
|
using PoweredSoft.DynamicLinq.Fluent;
|
2018-10-18 21:52:05 -04:00
|
|
|
|
using PoweredSoft.DynamicQuery.Core;
|
2018-10-17 22:14:21 -04:00
|
|
|
|
|
|
|
|
|
namespace PoweredSoft.DynamicQuery
|
|
|
|
|
{
|
2018-10-18 21:52:05 -04:00
|
|
|
|
public class QueryHandler : QueryHandlerBase, IQueryHandler
|
2018-10-17 22:14:21 -04:00
|
|
|
|
{
|
2018-10-18 21:52:05 -04:00
|
|
|
|
internal MethodInfo ExecuteGeneric = typeof(QueryHandler).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).First(t => t.Name == "Execute" && t.IsGenericMethod);
|
|
|
|
|
internal IQueryExecutionResult ExecuteReflected() => (IQueryExecutionResult)ExecuteGeneric.MakeGenericMethod(QueryableUnderlyingType).Invoke(this, new object[]{});
|
2018-10-17 22:14:21 -04:00
|
|
|
|
|
2018-10-18 21:52:05 -04:00
|
|
|
|
protected virtual IQueryExecutionResult Execute<T>()
|
2018-10-17 22:14:21 -04:00
|
|
|
|
{
|
2018-10-18 21:52:05 -04:00
|
|
|
|
ApplyIncludeStrategyInterceptors<T>();
|
|
|
|
|
ApplyBeforeFilterInterceptors<T>();
|
2018-10-17 22:14:21 -04:00
|
|
|
|
ApplyFilters<T>();
|
2018-10-18 21:52:05 -04:00
|
|
|
|
return HasGrouping ? ExecuteGrouping<T>() : ExecuteNoGrouping<T>();
|
2018-10-17 22:14:21 -04:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-18 21:52:05 -04:00
|
|
|
|
protected virtual IQueryExecutionResult ExecuteGrouping<T>()
|
2018-10-17 22:14:21 -04:00
|
|
|
|
{
|
2018-10-19 17:44:13 -04:00
|
|
|
|
var result = new GroupedQueryExecutionResult();
|
|
|
|
|
result.TotalRecords = CurrentQueryable.LongCount();
|
|
|
|
|
|
2018-10-21 14:15:21 -04:00
|
|
|
|
// intercept groups in advance to avoid doing it more than once :)
|
|
|
|
|
var finalGroups = Criteria.Groups.Select(g => InterceptGroup<T>(g)).ToList();
|
|
|
|
|
|
|
|
|
|
// get the aggregates.
|
|
|
|
|
List<List<DynamicClass>> aggregateResults = null;
|
|
|
|
|
if (Criteria.Aggregates.Any())
|
2018-10-19 17:44:13 -04:00
|
|
|
|
{
|
2018-10-21 14:15:21 -04:00
|
|
|
|
var previousGroups = new List<IGroup>();
|
|
|
|
|
aggregateResults = finalGroups.Select(fg =>
|
2018-10-19 17:44:13 -04:00
|
|
|
|
{
|
2018-10-21 14:15:21 -04:00
|
|
|
|
var groupExpression = CurrentQueryable.GroupBy(QueryableUnderlyingType, gb =>
|
|
|
|
|
{
|
|
|
|
|
previousGroups.ForEach(pg =>
|
|
|
|
|
{
|
|
|
|
|
var previousGroupCleanedPath = pg.Path.Replace(".", "");
|
|
|
|
|
gb.Path(pg.Path, $"Key_{previousGroupCleanedPath}");
|
|
|
|
|
});
|
|
|
|
|
var cleanedPath = fg.Path.Replace(".", "");
|
|
|
|
|
gb.Path(fg.Path, $"Key_{cleanedPath}");
|
|
|
|
|
});
|
2018-10-19 17:44:13 -04:00
|
|
|
|
|
2018-10-21 14:15:21 -04:00
|
|
|
|
var selectExpression = groupExpression.Select(sb =>
|
2018-10-19 17:44:13 -04:00
|
|
|
|
{
|
2018-10-21 14:15:21 -04:00
|
|
|
|
previousGroups.ForEach(pg => sb.Key(pg.Path));
|
|
|
|
|
sb.Key(fg.Path);
|
|
|
|
|
Criteria.Aggregates.ForEach(a =>
|
|
|
|
|
{
|
|
|
|
|
var selectType = ResolveSelectFrom(a.Type);
|
|
|
|
|
var pathCleaned = a.Path?.Replace(".", "");
|
|
|
|
|
sb.Aggregate(a.Path, selectType, $"Agg_{a.Type}_{pathCleaned}");
|
|
|
|
|
});
|
2018-10-19 17:44:13 -04:00
|
|
|
|
});
|
2018-10-21 14:15:21 -04:00
|
|
|
|
|
|
|
|
|
var aggregateResult = selectExpression.ToDynamicClassList();
|
|
|
|
|
previousGroups.Add(fg);
|
|
|
|
|
return aggregateResult;
|
|
|
|
|
}).ToList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// sorting.
|
|
|
|
|
finalGroups.ForEach(fg =>
|
|
|
|
|
{
|
|
|
|
|
Criteria.Sorts.Insert(0, new Sort()
|
|
|
|
|
{
|
|
|
|
|
Path = fg.Path,
|
|
|
|
|
Ascending = fg.Ascending
|
2018-10-19 17:44:13 -04:00
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2018-10-21 14:15:21 -04:00
|
|
|
|
ApplySorting<T>();
|
|
|
|
|
ApplyPaging<T>();
|
|
|
|
|
|
|
|
|
|
// now get the data grouped.
|
|
|
|
|
CurrentQueryable = CurrentQueryable.GroupBy(QueryableUnderlyingType, gb => finalGroups.ForEach(fg => gb.Path(fg.Path)));
|
|
|
|
|
CurrentQueryable = CurrentQueryable.Select(sb =>
|
|
|
|
|
{
|
|
|
|
|
finalGroups.ForEach(fg => sb.Key(fg.Path));
|
|
|
|
|
sb.ToList("Records");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var temp = CurrentQueryable.ToDynamicClassList();
|
|
|
|
|
|
2018-10-19 17:44:13 -04:00
|
|
|
|
return result;
|
2018-10-17 22:14:21 -04:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-19 17:44:13 -04:00
|
|
|
|
|
2018-10-21 14:15:21 -04:00
|
|
|
|
|
|
|
|
|
|
2018-10-18 21:52:05 -04:00
|
|
|
|
protected virtual IQueryExecutionResult ExecuteNoGrouping<T>()
|
2018-10-17 22:14:21 -04:00
|
|
|
|
{
|
2018-10-18 21:52:05 -04:00
|
|
|
|
var result = new QueryExecutionResult();
|
2018-10-17 22:14:21 -04:00
|
|
|
|
|
2018-10-18 21:52:05 -04:00
|
|
|
|
// total records.
|
|
|
|
|
result.TotalRecords = CurrentQueryable.LongCount();
|
2018-10-17 22:14:21 -04:00
|
|
|
|
|
2018-10-18 21:52:05 -04:00
|
|
|
|
// sorts and paging.
|
2018-10-21 14:15:21 -04:00
|
|
|
|
ApplySorting<T>();
|
|
|
|
|
ApplyPaging<T>();
|
2018-10-18 21:52:05 -04:00
|
|
|
|
|
|
|
|
|
// the data.
|
|
|
|
|
result.Data = CurrentQueryable.ToObjectList();
|
2018-10-17 22:14:21 -04:00
|
|
|
|
|
2018-10-18 21:52:05 -04:00
|
|
|
|
// if there is paging.
|
|
|
|
|
if (HasPaging)
|
|
|
|
|
{
|
|
|
|
|
if (result.TotalRecords < Criteria.PageSize)
|
|
|
|
|
result.NumberOfPages = 1;
|
|
|
|
|
else
|
|
|
|
|
result.NumberOfPages = result.TotalRecords / Criteria.PageSize + (result.TotalRecords % Criteria.PageSize != 0 ? 1 : 0);
|
|
|
|
|
}
|
2018-10-17 22:14:21 -04:00
|
|
|
|
|
2018-10-18 21:52:05 -04:00
|
|
|
|
return result;
|
2018-10-17 22:14:21 -04:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-18 21:52:05 -04:00
|
|
|
|
public virtual IQueryExecutionResult Execute(IQueryable queryable, IQueryCriteria criteria)
|
2018-10-17 22:14:21 -04:00
|
|
|
|
{
|
|
|
|
|
Reset(queryable, criteria);
|
2018-10-18 21:52:05 -04:00
|
|
|
|
return ExecuteReflected();
|
2018-10-17 22:14:21 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|