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; 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 Interceptors { get; } = new List(); 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; } public virtual void AddInterceptor(IQueryInterceptor interceptor) { if (interceptor == null) throw new ArgumentNullException("interceptor"); if (!Interceptors.Contains(interceptor)) Interceptors.Add(interceptor); } protected virtual IGroup InterceptGroup(IGroup group) { var ret = Interceptors .Where(t => t is IGroupingInterceptor) .Cast() .Aggregate(group, (prev, inter) => inter.InterceptGroup(prev)); return ret; } protected virtual void ApplyNoGroupingPaging() { if (!HasPaging) return; var q = (IQueryable) CurrentQueryable; var skip = ((Criteria.Page ?? 1) - 1) * Criteria.PageSize.Value; CurrentQueryable = q.Skip(skip).Take(Criteria.PageSize.Value); } protected virtual void ApplyNoGroupingSorts() { if (Criteria.Sorts?.Any() != true) { ApplyNoSortInterceptor(); return; } Criteria.Sorts.ForEach(sort => { var transformedSort = InterceptSort(sort); if (transformedSort.Count == 0) return; }); } protected virtual List InterceptSort(ISort sort) { var original = new List() { sort }; var ret = Interceptors .Where(t => t is ISortInterceptor) .Cast() .Aggregate(original as IEnumerable, (prev, inter) => inter.InterceptSort(prev)) .Distinct(); return ret.ToList(); } protected virtual void ApplyNoSortInterceptor() { CurrentQueryable = Interceptors.Where(t => t is INoSortInterceptor) .Cast() .Aggregate(CurrentQueryable, (prev, interceptor) => interceptor.InterceptNoSort(prev)); CurrentQueryable = Interceptors.Where(t => t is INoSortInterceptor) .Cast>() .Aggregate((IQueryable)CurrentQueryable, (prev, interceptor) => interceptor.InterceptNoSort(prev)); } protected virtual SelectTypes? ResolveSelectFromOrDefault(AggregateType aggregateType) => aggregateType.SelectType(); protected virtual ConditionOperators? ResolveConditionOperatorFromOrDefault(FilterType filterType) => filterType.ConditionOperator(); protected virtual ConditionOperators ResolveConditionOperatorFrom(FilterType filterType) { var ret = ResolveConditionOperatorFromOrDefault(filterType); if (ret == null) throw new NotSupportedException($"{filterType} is not supported"); return ret.Value; } protected virtual SelectTypes ResolveSelectFrom(AggregateType aggregateType) { var ret = ResolveSelectFromOrDefault(aggregateType); if (ret == null) throw new NotSupportedException($"{aggregateType} is not supported"); return ret.Value; } protected virtual void ApplyFilters() { if (true != Criteria.Filters?.Any()) return; CurrentQueryable = CurrentQueryable.Query(whereBuilder => { Criteria.Filters.ForEach(filter => ApplyFilter(whereBuilder, filter)); }); } protected virtual void ApplyFilter(WhereBuilder whereBuilder, IFilter filter) { var transformedFilter = InterceptFilter(filter); if (transformedFilter is ISimpleFilter) ApplySimpleFilter(whereBuilder, transformedFilter as ISimpleFilter); else if (transformedFilter is ICompositeFilter) AppleCompositeFilter(whereBuilder, transformedFilter as ICompositeFilter); else throw new NotSupportedException(); } protected virtual void AppleCompositeFilter(WhereBuilder whereBuilder, ICompositeFilter filter) { whereBuilder.SubQuery(subWhereBuilder => filter.Filters.ForEach(subFilter => ApplyFilter(subWhereBuilder, subFilter)), filter.And == true); } protected virtual void ApplySimpleFilter(WhereBuilder whereBuilder, ISimpleFilter filter) { var resolvedConditionOperator = ResolveConditionOperatorFrom(filter.Type); whereBuilder.Compare(filter.Path, resolvedConditionOperator, filter.Value, and: filter.And == true); } protected virtual IFilter InterceptFilter(IFilter filter) { var ret = Interceptors.Where(t => t is IFilterInterceptor) .Cast() .Aggregate(filter, (previousFilter, interceptor) => interceptor.InterceptFilter(previousFilter)); return ret; } protected virtual void ApplyIncludeStrategyInterceptors() { CurrentQueryable = Interceptors .Where(t => t is IIncludeStrategyInterceptor) .Cast() .Aggregate(CurrentQueryable, (prev, interceptor) => interceptor.InterceptIncludeStrategy(Criteria, prev)); CurrentQueryable = Interceptors .Where(t => t is IIncludeStrategyInterceptor) .Cast>() .Aggregate((IQueryable)CurrentQueryable, (prev, interceptor) => interceptor.InterceptIncludeStrategy(Criteria, prev)); } protected virtual void ApplyBeforeFilterInterceptors() { CurrentQueryable = Interceptors .Where(t => t is IBeforeQueryFilterInterceptor) .Cast() .Aggregate(CurrentQueryable, (prev, interceptor) => interceptor.InterceptBeforeFiltering(Criteria, prev)); CurrentQueryable = Interceptors .Where(t => t is IBeforeQueryFilterInterceptor) .Cast>() .Aggregate((IQueryable)CurrentQueryable, (prev, interceptor) => interceptor.InterceptBeforeFiltering(Criteria, prev)); } } }