2018-10-18 21:52:05 -04:00
|
|
|
|
using PoweredSoft.DynamicQuery.Core;
|
|
|
|
|
using PoweredSoft.DynamicLinq;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Net;
|
|
|
|
|
using System.Reflection;
|
2018-10-21 17:37:59 -04:00
|
|
|
|
using System.Runtime.CompilerServices;
|
2018-10-18 21:52:05 -04:00
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using PoweredSoft.DynamicLinq.Fluent;
|
|
|
|
|
using PoweredSoft.DynamicQuery.Extensions;
|
|
|
|
|
|
|
|
|
|
namespace PoweredSoft.DynamicQuery
|
|
|
|
|
{
|
|
|
|
|
public abstract class QueryHandlerBase : IInterceptableQueryHandler
|
|
|
|
|
{
|
|
|
|
|
protected List<IQueryInterceptor> Interceptors { get; } = new List<IQueryInterceptor>();
|
|
|
|
|
protected IQueryCriteria Criteria { get; set; }
|
|
|
|
|
protected IQueryable QueryableAtStart { get; private set; }
|
|
|
|
|
protected IQueryable CurrentQueryable { get; set; }
|
|
|
|
|
protected Type QueryableUnderlyingType => QueryableAtStart.ElementType;
|
|
|
|
|
protected bool HasGrouping => Criteria.Groups?.Any() == true;
|
|
|
|
|
protected bool HasPaging => Criteria.PageSize.HasValue && Criteria.PageSize > 0;
|
|
|
|
|
|
|
|
|
|
protected virtual void Reset(IQueryable queryable, IQueryCriteria criteria)
|
|
|
|
|
{
|
|
|
|
|
Criteria = criteria ?? throw new ArgumentNullException("criteria");
|
|
|
|
|
QueryableAtStart = queryable ?? throw new ArgumentNullException("queryable");
|
|
|
|
|
CurrentQueryable = QueryableAtStart;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual void CommonBeforeExecute<TSource>()
|
2018-12-06 22:24:03 -05:00
|
|
|
|
{
|
2019-03-19 23:54:15 -04:00
|
|
|
|
ApplyIncludeStrategyInterceptors<TSource>();
|
|
|
|
|
ApplyBeforeFilterInterceptors<TSource>();
|
|
|
|
|
ApplyFilters<TSource>();
|
2018-12-06 22:24:03 -05:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-18 21:52:05 -04:00
|
|
|
|
public virtual void AddInterceptor(IQueryInterceptor interceptor)
|
|
|
|
|
{
|
|
|
|
|
if (interceptor == null) throw new ArgumentNullException("interceptor");
|
|
|
|
|
|
|
|
|
|
if (!Interceptors.Contains(interceptor))
|
|
|
|
|
Interceptors.Add(interceptor);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual IGroup InterceptGroup<TSource>(IGroup group)
|
2018-10-19 17:44:13 -04:00
|
|
|
|
{
|
|
|
|
|
var ret = Interceptors
|
2018-10-23 22:38:28 -04:00
|
|
|
|
.Where(t => t is IGroupInterceptor)
|
|
|
|
|
.Cast<IGroupInterceptor>()
|
2018-10-19 17:44:13 -04:00
|
|
|
|
.Aggregate(group, (prev, inter) => inter.InterceptGroup(prev));
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual void ApplyPaging<TSource>()
|
2018-10-18 21:52:05 -04:00
|
|
|
|
{
|
|
|
|
|
if (!HasPaging)
|
|
|
|
|
return;
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
var q = (IQueryable<TSource>) CurrentQueryable;
|
2018-10-18 21:52:05 -04:00
|
|
|
|
var skip = ((Criteria.Page ?? 1) - 1) * Criteria.PageSize.Value;
|
|
|
|
|
CurrentQueryable = q.Skip(skip).Take(Criteria.PageSize.Value);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual void ApplySorting<TSource>()
|
2018-10-18 21:52:05 -04:00
|
|
|
|
{
|
|
|
|
|
if (Criteria.Sorts?.Any() != true)
|
|
|
|
|
{
|
2019-03-19 23:54:15 -04:00
|
|
|
|
ApplyNoSortInterceptor<TSource>();
|
2018-10-18 21:52:05 -04:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-22 23:08:27 -04:00
|
|
|
|
bool isAppending = false;
|
2018-10-18 21:52:05 -04:00
|
|
|
|
Criteria.Sorts.ForEach(sort =>
|
|
|
|
|
{
|
2019-03-19 23:54:15 -04:00
|
|
|
|
var transformedSort = InterceptSort<TSource>(sort);
|
2018-10-18 21:52:05 -04:00
|
|
|
|
if (transformedSort.Count == 0)
|
|
|
|
|
return;
|
2018-10-22 23:08:27 -04:00
|
|
|
|
|
|
|
|
|
transformedSort.ForEach(ts =>
|
|
|
|
|
{
|
|
|
|
|
CurrentQueryable = CurrentQueryable.OrderBy(ts.Path, ts.Ascending == false ? QueryOrderByDirection.Descending : QueryOrderByDirection.Ascending, isAppending);
|
|
|
|
|
isAppending = true;
|
|
|
|
|
});
|
2018-10-18 21:52:05 -04:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected DynamicClass FindMatchingAggregateResult<TRecord>(List<List<DynamicClass>> aggregateResults, List<IGroup> groups, List<IGroupQueryResult<TRecord>> groupResults)
|
2018-12-06 22:24:03 -05:00
|
|
|
|
{
|
|
|
|
|
var groupIndex = groupResults.Count - 1;
|
|
|
|
|
var aggregateLevel = aggregateResults[groupIndex];
|
|
|
|
|
|
|
|
|
|
var ret = aggregateLevel.FirstOrDefault(al =>
|
|
|
|
|
{
|
|
|
|
|
for (var i = 0; i < groups.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
if (!al.GetDynamicPropertyValue($"Key_{i}").Equals(groupResults[i].GroupValue))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual IQueryable CreateFetchAggregateSelectExpression<TSource>(IGroup finalGroup, List<IGroup> previousGroups)
|
2018-12-06 22:24:03 -05:00
|
|
|
|
{
|
|
|
|
|
var groupExpression = CurrentQueryable.GroupBy(QueryableUnderlyingType, gb =>
|
|
|
|
|
{
|
|
|
|
|
var groupKeyIndex = -1;
|
|
|
|
|
previousGroups.ForEach(pg => gb.Path(pg.Path, $"Key_{++groupKeyIndex}"));
|
|
|
|
|
gb.Path(finalGroup.Path, $"Key_{++groupKeyIndex}");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var selectExpression = groupExpression.Select(sb =>
|
|
|
|
|
{
|
|
|
|
|
var groupKeyIndex = -1;
|
|
|
|
|
previousGroups.ForEach(pg => sb.Key($"Key_{++groupKeyIndex}", $"Key_{groupKeyIndex}"));
|
|
|
|
|
sb.Key($"Key_{++groupKeyIndex}", $"Key_{groupKeyIndex}");
|
|
|
|
|
Criteria.Aggregates.ForEach((a, ai) =>
|
|
|
|
|
{
|
2019-03-19 23:54:15 -04:00
|
|
|
|
var fa = InterceptAggregate<TSource>(a);
|
2018-12-06 22:24:03 -05:00
|
|
|
|
var selectType = ResolveSelectFrom(fa.Type);
|
|
|
|
|
sb.Aggregate(fa.Path, selectType, $"Agg_{ai}");
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
return selectExpression;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected virtual List<IAggregateResult> MaterializeCalculateTotalAggregateResult(DynamicClass aggregateResult)
|
|
|
|
|
{
|
|
|
|
|
var ret = new List<IAggregateResult>();
|
|
|
|
|
Criteria.Aggregates.ForEach((a, index) =>
|
|
|
|
|
{
|
|
|
|
|
ret.Add(new AggregateResult()
|
|
|
|
|
{
|
|
|
|
|
Path = a.Path,
|
|
|
|
|
Type = a.Type,
|
|
|
|
|
Value = aggregateResult?.GetDynamicPropertyValue($"Agg_{index}")
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual IQueryable CreateTotalAggregateSelectExpression<TSource>(IQueryable queryableAfterFilters)
|
2018-12-06 22:24:03 -05:00
|
|
|
|
{
|
|
|
|
|
var groupExpression = queryableAfterFilters.EmptyGroupBy(QueryableUnderlyingType);
|
|
|
|
|
var selectExpression = groupExpression.Select(sb =>
|
|
|
|
|
{
|
|
|
|
|
Criteria.Aggregates.ForEach((a, index) =>
|
|
|
|
|
{
|
2019-03-19 23:54:15 -04:00
|
|
|
|
var fa = InterceptAggregate<TSource>(a);
|
2018-12-06 22:24:03 -05:00
|
|
|
|
var selectType = ResolveSelectFrom(fa.Type);
|
|
|
|
|
sb.Aggregate(fa.Path, selectType, $"Agg_{index}");
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
return selectExpression;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual void CalculatePageCount(IQueryExecutionResultPaging result)
|
2018-10-21 15:15:26 -04:00
|
|
|
|
{
|
|
|
|
|
if (!HasPaging)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (result.TotalRecords < Criteria.PageSize)
|
|
|
|
|
result.NumberOfPages = 1;
|
|
|
|
|
else
|
|
|
|
|
result.NumberOfPages = result.TotalRecords / Criteria.PageSize + (result.TotalRecords % Criteria.PageSize != 0 ? 1 : 0);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual IAggregate InterceptAggregate<TSource>(IAggregate aggregate)
|
2018-10-21 17:37:59 -04:00
|
|
|
|
{
|
|
|
|
|
var ret = Interceptors
|
|
|
|
|
.Where(t => t is IAggregateInterceptor)
|
|
|
|
|
.Cast<IAggregateInterceptor>()
|
|
|
|
|
.Aggregate(aggregate, (prev, inter) => inter.InterceptAggregate(prev));
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2018-10-21 15:15:26 -04:00
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual async Task<List<TRecord>> InterceptConvertTo<TSource, TRecord>(List<TSource> entities)
|
2018-10-21 21:27:50 -04:00
|
|
|
|
{
|
2019-02-23 23:47:50 -05:00
|
|
|
|
await AfterEntityReadInterceptors(entities);
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
var ret = new List<TRecord>();
|
|
|
|
|
for (var i = 0; i < entities.Count; i++)
|
|
|
|
|
ret.Add(InterceptConvertToObject<TSource, TRecord>(entities[i]));
|
2018-10-21 21:27:50 -04:00
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
var pairs = entities.Select((t, index) => Tuple.Create(t, (object)ret[index])).ToList();
|
|
|
|
|
await AfterReadInterceptors<TSource, TRecord>(pairs);
|
2019-02-23 23:47:50 -05:00
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
return ret;
|
2018-10-21 21:27:50 -04:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual async Task AfterEntityReadInterceptors<TSource>(List<TSource> entities)
|
2019-02-23 23:47:50 -05:00
|
|
|
|
{
|
|
|
|
|
Interceptors
|
2019-03-19 23:54:15 -04:00
|
|
|
|
.Where(t => t is IAfterReadEntityInterceptor<TSource>)
|
|
|
|
|
.Cast<IAfterReadEntityInterceptor<TSource>>()
|
2019-02-23 23:47:50 -05:00
|
|
|
|
.ToList()
|
|
|
|
|
.ForEach(t => t.AfterReadEntity(entities));
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
var asyncInterceptors = Interceptors.Where(t => t is IAfterReadEntityInterceptorAsync<TSource>).Cast<IAfterReadEntityInterceptorAsync<TSource>>();
|
2019-02-23 23:47:50 -05:00
|
|
|
|
foreach (var interceptor in asyncInterceptors)
|
|
|
|
|
await interceptor.AfterReadEntityAsync(entities);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual async Task AfterReadInterceptors<TSource, TRecord>(List<Tuple<TSource, object>> pairs)
|
2019-02-23 23:47:50 -05:00
|
|
|
|
{
|
|
|
|
|
Interceptors
|
2019-03-19 23:54:15 -04:00
|
|
|
|
.Where(t => t is IAfterReadInterceptor<TSource>)
|
|
|
|
|
.Cast<IAfterReadInterceptor<TSource>>()
|
2019-02-23 23:47:50 -05:00
|
|
|
|
.ToList()
|
|
|
|
|
.ForEach(t => t.AfterRead(pairs));
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
var asyncInterceptors = Interceptors.Where(t => t is IAfterReadInterceptorAsync<TSource>).Cast<IAfterReadInterceptorAsync<TSource>>();
|
2019-02-23 23:47:50 -05:00
|
|
|
|
foreach (var interceptor in asyncInterceptors)
|
|
|
|
|
await interceptor.AfterReadAsync(pairs);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual TRecord InterceptConvertToObject<TSource, TRecord>(object o)
|
2018-10-21 21:27:50 -04:00
|
|
|
|
{
|
|
|
|
|
o = Interceptors
|
|
|
|
|
.Where(t => t is IQueryConvertInterceptor)
|
|
|
|
|
.Cast<IQueryConvertInterceptor>()
|
|
|
|
|
.Aggregate(o, (prev, interceptor) => interceptor.InterceptResultTo(prev));
|
|
|
|
|
|
|
|
|
|
o = Interceptors
|
2019-03-19 23:54:15 -04:00
|
|
|
|
.Where(t => t is IQueryConvertInterceptor<TSource>)
|
|
|
|
|
.Cast<IQueryConvertInterceptor<TSource>>()
|
2018-10-21 21:27:50 -04:00
|
|
|
|
.Aggregate(o, (prev, interceptor) =>
|
|
|
|
|
{
|
2019-03-19 23:54:15 -04:00
|
|
|
|
if (prev is TSource)
|
|
|
|
|
return interceptor.InterceptResultTo((TSource)prev);
|
2018-10-21 21:27:50 -04:00
|
|
|
|
|
|
|
|
|
return o;
|
|
|
|
|
});
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
return (TRecord)o;
|
2018-10-21 21:27:50 -04:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual List<ISort> InterceptSort<TSource>(ISort sort)
|
2018-10-18 21:52:05 -04:00
|
|
|
|
{
|
2018-10-19 17:44:13 -04:00
|
|
|
|
var original = new List<ISort>()
|
|
|
|
|
{
|
|
|
|
|
sort
|
|
|
|
|
};
|
|
|
|
|
|
2018-10-18 21:52:05 -04:00
|
|
|
|
var ret = Interceptors
|
|
|
|
|
.Where(t => t is ISortInterceptor)
|
|
|
|
|
.Cast<ISortInterceptor>()
|
2018-10-19 17:44:13 -04:00
|
|
|
|
.Aggregate(original as IEnumerable<ISort>, (prev, inter) => inter.InterceptSort(prev))
|
|
|
|
|
.Distinct();
|
2018-10-18 21:52:05 -04:00
|
|
|
|
|
2018-10-19 17:44:13 -04:00
|
|
|
|
return ret.ToList();
|
2018-10-18 21:52:05 -04:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual void ApplyNoSortInterceptor<TSource>()
|
2018-10-18 21:52:05 -04:00
|
|
|
|
{
|
|
|
|
|
CurrentQueryable = Interceptors.Where(t => t is INoSortInterceptor)
|
|
|
|
|
.Cast<INoSortInterceptor>()
|
2018-10-23 18:42:53 -04:00
|
|
|
|
.Aggregate(CurrentQueryable, (prev, interceptor) => interceptor.InterceptNoSort(Criteria, prev));
|
2018-10-18 21:52:05 -04:00
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
CurrentQueryable = Interceptors.Where(t => t is INoSortInterceptor<TSource>)
|
|
|
|
|
.Cast<INoSortInterceptor<TSource>>()
|
|
|
|
|
.Aggregate((IQueryable<TSource>)CurrentQueryable, (prev, interceptor) => interceptor.InterceptNoSort(Criteria, prev));
|
2018-10-18 21:52:05 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-10-19 17:44:13 -04:00
|
|
|
|
protected virtual SelectTypes? ResolveSelectFromOrDefault(AggregateType aggregateType) => aggregateType.SelectType();
|
|
|
|
|
protected virtual ConditionOperators? ResolveConditionOperatorFromOrDefault(FilterType filterType) => filterType.ConditionOperator();
|
|
|
|
|
|
|
|
|
|
protected virtual ConditionOperators ResolveConditionOperatorFrom(FilterType filterType)
|
2018-10-18 21:52:05 -04:00
|
|
|
|
{
|
2018-10-19 17:44:13 -04:00
|
|
|
|
var ret = ResolveConditionOperatorFromOrDefault(filterType);
|
2018-10-18 21:52:05 -04:00
|
|
|
|
if (ret == null)
|
|
|
|
|
throw new NotSupportedException($"{filterType} is not supported");
|
|
|
|
|
|
|
|
|
|
return ret.Value;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-19 17:44:13 -04:00
|
|
|
|
protected virtual SelectTypes ResolveSelectFrom(AggregateType aggregateType)
|
|
|
|
|
{
|
|
|
|
|
var ret = ResolveSelectFromOrDefault(aggregateType);
|
|
|
|
|
if (ret == null)
|
|
|
|
|
throw new NotSupportedException($"{aggregateType} is not supported");
|
|
|
|
|
|
|
|
|
|
return ret.Value;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual void ApplyFilters<TSource>()
|
2018-10-18 21:52:05 -04:00
|
|
|
|
{
|
|
|
|
|
if (true != Criteria.Filters?.Any())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
CurrentQueryable = CurrentQueryable.Query(whereBuilder =>
|
|
|
|
|
{
|
2019-03-19 23:54:15 -04:00
|
|
|
|
Criteria.Filters.ForEach(filter => ApplyFilter<TSource>(whereBuilder, filter));
|
2018-10-18 21:52:05 -04:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual void ApplyFilter<TSource>(WhereBuilder whereBuilder, IFilter filter)
|
2018-10-18 21:52:05 -04:00
|
|
|
|
{
|
2019-03-19 23:54:15 -04:00
|
|
|
|
var transformedFilter = InterceptFilter<TSource>(filter);
|
2018-10-18 21:52:05 -04:00
|
|
|
|
if (transformedFilter is ISimpleFilter)
|
2019-03-19 23:54:15 -04:00
|
|
|
|
ApplySimpleFilter<TSource>(whereBuilder, transformedFilter as ISimpleFilter);
|
2018-10-18 21:52:05 -04:00
|
|
|
|
else if (transformedFilter is ICompositeFilter)
|
2019-03-19 23:54:15 -04:00
|
|
|
|
AppleCompositeFilter<TSource>(whereBuilder, transformedFilter as ICompositeFilter);
|
2018-10-18 21:52:05 -04:00
|
|
|
|
else
|
|
|
|
|
throw new NotSupportedException();
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual void AppleCompositeFilter<TSource>(WhereBuilder whereBuilder, ICompositeFilter filter)
|
2018-10-18 21:52:05 -04:00
|
|
|
|
{
|
2019-03-19 23:54:15 -04:00
|
|
|
|
whereBuilder.SubQuery(subWhereBuilder => filter.Filters.ForEach(subFilter => ApplyFilter<TSource>(subWhereBuilder, subFilter)), filter.And == true);
|
2018-10-18 21:52:05 -04:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual void ApplySimpleFilter<TSource>(WhereBuilder whereBuilder, ISimpleFilter filter)
|
2018-10-18 21:52:05 -04:00
|
|
|
|
{
|
2018-10-19 17:44:13 -04:00
|
|
|
|
var resolvedConditionOperator = ResolveConditionOperatorFrom(filter.Type);
|
2018-10-18 21:52:05 -04:00
|
|
|
|
whereBuilder.Compare(filter.Path, resolvedConditionOperator, filter.Value, and: filter.And == true);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual IFilter InterceptFilter<TSource>(IFilter filter)
|
2018-10-18 21:52:05 -04:00
|
|
|
|
{
|
|
|
|
|
var ret = Interceptors.Where(t => t is IFilterInterceptor)
|
|
|
|
|
.Cast<IFilterInterceptor>()
|
|
|
|
|
.Aggregate(filter, (previousFilter, interceptor) => interceptor.InterceptFilter(previousFilter));
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual void ApplyIncludeStrategyInterceptors<TSource>()
|
2018-10-18 21:52:05 -04:00
|
|
|
|
{
|
|
|
|
|
CurrentQueryable = Interceptors
|
|
|
|
|
.Where(t => t is IIncludeStrategyInterceptor)
|
|
|
|
|
.Cast<IIncludeStrategyInterceptor>()
|
|
|
|
|
.Aggregate(CurrentQueryable, (prev, interceptor) => interceptor.InterceptIncludeStrategy(Criteria, prev));
|
|
|
|
|
|
|
|
|
|
CurrentQueryable = Interceptors
|
2019-03-19 23:54:15 -04:00
|
|
|
|
.Where(t => t is IIncludeStrategyInterceptor<TSource>)
|
|
|
|
|
.Cast<IIncludeStrategyInterceptor<TSource>>()
|
|
|
|
|
.Aggregate((IQueryable<TSource>)CurrentQueryable, (prev, interceptor) => interceptor.InterceptIncludeStrategy(Criteria, prev));
|
2018-10-18 21:52:05 -04:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual void ApplyBeforeFilterInterceptors<TSource>()
|
2018-10-18 21:52:05 -04:00
|
|
|
|
{
|
|
|
|
|
CurrentQueryable = Interceptors
|
|
|
|
|
.Where(t => t is IBeforeQueryFilterInterceptor)
|
|
|
|
|
.Cast<IBeforeQueryFilterInterceptor>()
|
|
|
|
|
.Aggregate(CurrentQueryable, (prev, interceptor) => interceptor.InterceptBeforeFiltering(Criteria, prev));
|
|
|
|
|
|
|
|
|
|
CurrentQueryable = Interceptors
|
2019-03-19 23:54:15 -04:00
|
|
|
|
.Where(t => t is IBeforeQueryFilterInterceptor<TSource>)
|
|
|
|
|
.Cast<IBeforeQueryFilterInterceptor<TSource>>()
|
|
|
|
|
.Aggregate((IQueryable<TSource>)CurrentQueryable, (prev, interceptor) => interceptor.InterceptBeforeFiltering(Criteria, prev));
|
2018-10-18 21:52:05 -04:00
|
|
|
|
}
|
2018-12-06 22:24:03 -05:00
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual List<IGroupQueryResult<TRecord>> RecursiveRegroup<TSource, TRecord>(List<DynamicClass> groupRecords, List<List<DynamicClass>> aggregateResults, IGroup group, List<(List<TSource> entities, IGroupQueryResult<TRecord> group)> lastLists, List<IGroupQueryResult<TRecord>> parentGroupResults = null)
|
2018-12-06 22:24:03 -05:00
|
|
|
|
{
|
|
|
|
|
var groupIndex = Criteria.Groups.IndexOf(group);
|
|
|
|
|
var isLast = Criteria.Groups.Last() == group;
|
|
|
|
|
var groups = Criteria.Groups.Take(groupIndex + 1).ToList();
|
|
|
|
|
var hasAggregates = Criteria.Aggregates.Any();
|
|
|
|
|
|
|
|
|
|
var ret = groupRecords
|
|
|
|
|
.GroupBy(gk => gk.GetDynamicPropertyValue($"Key_{groupIndex}"))
|
|
|
|
|
.Select(t =>
|
|
|
|
|
{
|
2019-03-19 23:54:15 -04:00
|
|
|
|
var groupResult = new GroupQueryResult<TRecord>();
|
2018-12-06 22:24:03 -05:00
|
|
|
|
|
|
|
|
|
// group results.
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
List<IGroupQueryResult<TRecord>> groupResults;
|
2018-12-06 22:24:03 -05:00
|
|
|
|
if (parentGroupResults == null)
|
2019-03-19 23:54:15 -04:00
|
|
|
|
groupResults = new List<IGroupQueryResult<TRecord>> { groupResult };
|
2018-12-06 22:24:03 -05:00
|
|
|
|
else
|
|
|
|
|
groupResults = parentGroupResults.Union(new[] { groupResult }).ToList();
|
|
|
|
|
|
|
|
|
|
groupResult.GroupPath = group.Path;
|
|
|
|
|
groupResult.GroupValue = t.Key;
|
|
|
|
|
|
|
|
|
|
if (hasAggregates)
|
|
|
|
|
{
|
|
|
|
|
var matchingAggregate = FindMatchingAggregateResult(aggregateResults, groups, groupResults);
|
|
|
|
|
if (matchingAggregate == null)
|
|
|
|
|
Debugger.Break();
|
|
|
|
|
|
|
|
|
|
groupResult.Aggregates = new List<IAggregateResult>();
|
|
|
|
|
Criteria.Aggregates.ForEach((a, ai) =>
|
|
|
|
|
{
|
|
|
|
|
var key = $"Agg_{ai}";
|
|
|
|
|
var aggregateResult = new AggregateResult
|
|
|
|
|
{
|
|
|
|
|
Path = a.Path,
|
|
|
|
|
Type = a.Type,
|
|
|
|
|
Value = matchingAggregate.GetDynamicPropertyValue(key)
|
|
|
|
|
};
|
|
|
|
|
groupResult.Aggregates.Add(aggregateResult);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isLast)
|
|
|
|
|
{
|
2019-03-19 23:54:15 -04:00
|
|
|
|
var entities = t.SelectMany(t2 => t2.GetDynamicPropertyValue<List<TSource>>("Records")).ToList();
|
|
|
|
|
var tuple = (entities, groupResult);
|
|
|
|
|
groupResult.Data = new List<TRecord>();
|
|
|
|
|
lastLists.Add(tuple);
|
2018-12-06 22:24:03 -05:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-03-19 23:54:15 -04:00
|
|
|
|
groupResult.SubGroups = RecursiveRegroup<TSource, TRecord>(t.ToList(), aggregateResults, Criteria.Groups[groupIndex + 1], lastLists, groupResults);
|
2018-12-06 22:24:03 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return groupResult;
|
|
|
|
|
})
|
2019-03-19 23:54:15 -04:00
|
|
|
|
.AsEnumerable<IGroupQueryResult<TRecord>>()
|
2018-12-06 22:24:03 -05:00
|
|
|
|
.ToList();
|
2019-03-19 23:54:15 -04:00
|
|
|
|
|
2018-12-06 22:24:03 -05:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
2019-02-23 23:47:50 -05:00
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
protected virtual async Task QueryInterceptToGrouped<TSource, TRecord>(List<(List<TSource> entities, IGroupQueryResult<TRecord> group)> lists)
|
2019-02-23 23:47:50 -05:00
|
|
|
|
{
|
2019-03-19 23:54:15 -04:00
|
|
|
|
var entities = lists.SelectMany(t => t.entities).ToList();
|
2019-02-23 23:47:50 -05:00
|
|
|
|
await AfterEntityReadInterceptors(entities);
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
var pairs = new List<Tuple<TSource, object>>();
|
2019-02-23 23:47:50 -05:00
|
|
|
|
|
|
|
|
|
lists.ForEach(innerList =>
|
|
|
|
|
{
|
2019-03-19 23:54:15 -04:00
|
|
|
|
for (var i = 0; i < innerList.entities.Count; i++)
|
2019-02-23 23:47:50 -05:00
|
|
|
|
{
|
2019-03-19 23:54:15 -04:00
|
|
|
|
var entity = innerList.entities[i];
|
|
|
|
|
var convertedObject = InterceptConvertToObject<TSource, TRecord>(entity);
|
|
|
|
|
innerList.group.Data.Add(convertedObject);
|
|
|
|
|
pairs.Add(Tuple.Create(entity, convertedObject as object));
|
2019-02-23 23:47:50 -05:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2019-03-19 23:54:15 -04:00
|
|
|
|
await AfterReadInterceptors<TSource, TRecord>(pairs);
|
2019-02-23 23:47:50 -05:00
|
|
|
|
}
|
2018-10-18 21:52:05 -04:00
|
|
|
|
}
|
|
|
|
|
}
|