basic querying not async.
This commit is contained in:
parent
369c6f117f
commit
65db65171a
@ -5,6 +5,10 @@
|
|||||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\PoweredSoft.DynamicQuery.Core\PoweredSoft.DynamicQuery.Core.csproj" />
|
<ProjectReference Include="..\PoweredSoft.DynamicQuery.Core\PoweredSoft.DynamicQuery.Core.csproj" />
|
||||||
<ProjectReference Include="..\PoweredSoft.DynamicQuery\PoweredSoft.DynamicQuery.csproj" />
|
<ProjectReference Include="..\PoweredSoft.DynamicQuery\PoweredSoft.DynamicQuery.csproj" />
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
|
||||||
namespace PoweredSoft.DynamicQuery.Cli
|
namespace PoweredSoft.DynamicQuery.Cli
|
||||||
{
|
{
|
||||||
@ -73,26 +75,42 @@ namespace PoweredSoft.DynamicQuery.Cli
|
|||||||
};
|
};
|
||||||
|
|
||||||
var queryable = list.AsQueryable();
|
var queryable = list.AsQueryable();
|
||||||
|
|
||||||
var criteria = new QueryCriteria();
|
var criteria = new QueryCriteria();
|
||||||
|
criteria.Page = 1;
|
||||||
|
criteria.PageSize = 10;
|
||||||
|
|
||||||
criteria.Filters.Add(new SimpleFilter
|
criteria.Filters = new List<IFilter>
|
||||||
{
|
{
|
||||||
Path = "LastName",
|
new SimpleFilter() {Path = nameof(Person.LastName), Value = "Lebee", Type = FilterType.Equal},
|
||||||
Value = "Lebee",
|
new CompositeFilter()
|
||||||
Type = FilterType.Equal,
|
{
|
||||||
});
|
Type = FilterType.Composite,
|
||||||
|
And = true,
|
||||||
criteria.Filters.Add(new SimpleFilter
|
Filters = new List<IFilter>
|
||||||
{
|
{
|
||||||
Path = "FirstName",
|
new SimpleFilter() {Path = nameof(Person.FirstName), Value = "David", Type = FilterType.Equal},
|
||||||
Value = "David,Michaela",
|
new SimpleFilter() {Path = nameof(Person.FirstName), Value = "Zohra", Type = FilterType.Equal},
|
||||||
Type = FilterType.Equal,
|
}
|
||||||
});
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var handler = new QueryHandler();
|
var handler = new QueryHandler();
|
||||||
handler.AddInterceptor(new PersonQueryInterceptor());
|
handler.AddInterceptor(new PersonQueryInterceptor());
|
||||||
handler.Execute(queryable, criteria);
|
var result = handler.Execute(queryable, criteria);
|
||||||
|
|
||||||
|
var jsonSettings = new JsonSerializerSettings()
|
||||||
|
{
|
||||||
|
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
|
||||||
|
};
|
||||||
|
|
||||||
|
jsonSettings.Converters.Add(new StringEnumConverter { AllowIntegerValues = false });
|
||||||
|
|
||||||
|
Console.WriteLine("Request:\n");
|
||||||
|
Console.WriteLine(JsonConvert.SerializeObject(criteria, Formatting.Indented, jsonSettings));
|
||||||
|
Console.WriteLine("");
|
||||||
|
Console.WriteLine("Response:\n");
|
||||||
|
Console.WriteLine(JsonConvert.SerializeObject(result, Formatting.Indented, jsonSettings));
|
||||||
|
Console.ReadKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace PoweredSoft.DynamicQuery.Core
|
|
||||||
{
|
|
||||||
public interface IBeforeQueryAlteredInterceptor : IQueryInterceptor
|
|
||||||
{
|
|
||||||
IQueryable InterceptQueryBeforeAltered(IQueryCriteria criteria, IQueryable queryable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IBeforeQueryAlteredInterceptor<T> : IQueryInterceptor
|
|
||||||
{
|
|
||||||
IQueryable<T> InterceptQueryBeforeAltered(IQueryCriteria criteria, IQueryable<T> queryable);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace PoweredSoft.DynamicQuery.Core
|
|
||||||
{
|
|
||||||
public interface IBeforeQueryExecuteInterceptor : IQueryInterceptor
|
|
||||||
{
|
|
||||||
IQueryable InterceptBeforeQuery(IQueryCriteria criteria, IQueryable queryable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IBeforeQueryExecuteInterceptor<T> : IQueryInterceptor
|
|
||||||
{
|
|
||||||
IQueryable<T> InterceptBeforeQuery(IQueryCriteria criteria, IQueryable<T> queryable);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,14 @@
|
|||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace PoweredSoft.DynamicQuery.Core
|
||||||
|
{
|
||||||
|
public interface IBeforeQueryFilterInterceptor : IQueryInterceptor
|
||||||
|
{
|
||||||
|
IQueryable InterceptBeforeFiltering(IQueryCriteria criteria, IQueryable queryable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IBeforeQueryFilterInterceptor<T> : IQueryInterceptor
|
||||||
|
{
|
||||||
|
IQueryable<T> InterceptBeforeFiltering(IQueryCriteria criteria, IQueryable<T> queryable);
|
||||||
|
}
|
||||||
|
}
|
17
PoweredSoft.DynamicQuery.Core/IIncludeStrategyInterceptor.cs
Normal file
17
PoweredSoft.DynamicQuery.Core/IIncludeStrategyInterceptor.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace PoweredSoft.DynamicQuery.Core
|
||||||
|
{
|
||||||
|
public interface IIncludeStrategyInterceptor : IQueryInterceptor
|
||||||
|
{
|
||||||
|
IQueryable InterceptIncludeStrategy(IQueryCriteria criteria, IQueryable queryable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IIncludeStrategyInterceptor<T> : IQueryInterceptor
|
||||||
|
{
|
||||||
|
IQueryable<T> InterceptIncludeStrategy(IQueryCriteria criteria, IQueryable<T> queryable);
|
||||||
|
}
|
||||||
|
}
|
14
PoweredSoft.DynamicQuery.Core/INoSortInterceptor.cs
Normal file
14
PoweredSoft.DynamicQuery.Core/INoSortInterceptor.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace PoweredSoft.DynamicQuery.Core
|
||||||
|
{
|
||||||
|
public interface INoSortInterceptor : IQueryInterceptor
|
||||||
|
{
|
||||||
|
IQueryable InterceptNoSort(IQueryable queryable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface INoSortInterceptor<T> : IQueryInterceptor
|
||||||
|
{
|
||||||
|
IQueryable<T> InterceptNoSort(IQueryable<T> queryable);
|
||||||
|
}
|
||||||
|
}
|
@ -5,10 +5,18 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace PoweredSoft.DynamicQuery.Core
|
namespace PoweredSoft.DynamicQuery.Core
|
||||||
{
|
{
|
||||||
public interface IQueryHandler
|
public interface IInterceptableQueryHandler
|
||||||
{
|
{
|
||||||
IQueryResult Execute(IQueryable queryable, IQueryCriteria criteria);
|
|
||||||
Task<IQueryResult> ExecuteAsync(IQueryable queryable, IQueryCriteria criteria);
|
|
||||||
void AddInterceptor(IQueryInterceptor interceptor);
|
void AddInterceptor(IQueryInterceptor interceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface IQueryHandler : IInterceptableQueryHandler
|
||||||
|
{
|
||||||
|
IQueryExecutionResult Execute(IQueryable queryable, IQueryCriteria criteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IAsyncQueryHandler : IInterceptableQueryHandler
|
||||||
|
{
|
||||||
|
Task<IQueryExecutionResult> ExecuteAsync(IQueryable queryable, IQueryCriteria criteria);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
namespace PoweredSoft.DynamicQuery.Core
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace PoweredSoft.DynamicQuery.Core
|
||||||
{
|
{
|
||||||
public interface IQueryInterceptor
|
public interface IQueryInterceptor
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -13,17 +13,21 @@ namespace PoweredSoft.DynamicQuery.Core
|
|||||||
|
|
||||||
public interface IQueryResult
|
public interface IQueryResult
|
||||||
{
|
{
|
||||||
long Count { get; }
|
|
||||||
List<IAggregateResult> Aggregates { get; }
|
List<IAggregateResult> Aggregates { get; }
|
||||||
}
|
|
||||||
|
|
||||||
public interface IQueryResultSimple : IQueryResult
|
|
||||||
{
|
|
||||||
List<object> Data { get; }
|
List<object> Data { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IQueryResultGrouped : IQueryResult
|
public interface IGroupQueryResult : IQueryResult
|
||||||
{
|
{
|
||||||
List<IQueryResult> Data { get; }
|
string GroupPath { get; set; }
|
||||||
|
object GroupValue { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface IQueryExecutionResult : IQueryResult
|
||||||
|
{
|
||||||
|
long TotalRecords { get; set; }
|
||||||
|
long? NumberOfPages { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace PoweredSoft.DynamicQuery.Core
|
namespace PoweredSoft.DynamicQuery.Core
|
||||||
{
|
{
|
||||||
public interface ISortInteceptor : IQueryInterceptor
|
public interface ISortInterceptor : IQueryInterceptor
|
||||||
{
|
{
|
||||||
IEnumerable<ISort> InterceptSort(ISort sort);
|
IEnumerable<ISort> InterceptSort(ISort sort);
|
||||||
}
|
}
|
@ -1,142 +1,61 @@
|
|||||||
using PoweredSoft.DynamicQuery.Core;
|
using System;
|
||||||
using PoweredSoft.DynamicLinq;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using PoweredSoft.DynamicLinq;
|
||||||
using PoweredSoft.DynamicLinq.Fluent;
|
using PoweredSoft.DynamicQuery.Core;
|
||||||
using PoweredSoft.DynamicQuery.Extensions;
|
|
||||||
|
|
||||||
namespace PoweredSoft.DynamicQuery
|
namespace PoweredSoft.DynamicQuery
|
||||||
{
|
{
|
||||||
public class QueryHandler : IQueryHandler
|
public class QueryHandler : QueryHandlerBase, IQueryHandler
|
||||||
{
|
{
|
||||||
protected List<IQueryInterceptor> Interceptors { get; } = new List<IQueryInterceptor>();
|
internal MethodInfo ExecuteGeneric = typeof(QueryHandler).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).First(t => t.Name == "Execute" && t.IsGenericMethod);
|
||||||
protected IQueryCriteria Criteria { get; set; }
|
internal IQueryExecutionResult ExecuteReflected() => (IQueryExecutionResult)ExecuteGeneric.MakeGenericMethod(QueryableUnderlyingType).Invoke(this, new object[]{});
|
||||||
protected IQueryable QueryableAtStart { get; private set; }
|
|
||||||
protected IQueryable CurrentQueryable { get; set; }
|
|
||||||
protected Type QueryableUnderlyingType => QueryableAtStart.ElementType;
|
|
||||||
private MethodInfo ApplyInterceptorsAndCriteriaMethod { get; } = typeof(QueryHandler).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).First(t => t.Name == "ApplyInterceptorsAndCriteria" && t.IsGenericMethod);
|
|
||||||
|
|
||||||
protected virtual void Reset(IQueryable queryable, IQueryCriteria criteria)
|
protected virtual IQueryExecutionResult Execute<T>()
|
||||||
{
|
{
|
||||||
Criteria = criteria ?? throw new ArgumentNullException("criteria");
|
ApplyIncludeStrategyInterceptors<T>();
|
||||||
QueryableAtStart = queryable ?? throw new ArgumentNullException("queryable");
|
ApplyBeforeFilterInterceptors<T>();
|
||||||
CurrentQueryable = QueryableAtStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void AddInterceptor(IQueryInterceptor interceptor)
|
|
||||||
{
|
|
||||||
if (interceptor == null) throw new ArgumentNullException("interceptor");
|
|
||||||
|
|
||||||
if (!Interceptors.Contains(interceptor))
|
|
||||||
Interceptors.Add(interceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void ApplyInterceptorsAndCriteria<T>()
|
|
||||||
{
|
|
||||||
ApplySimpleBeforeAlterInterceptors();
|
|
||||||
ApplyGenericBeforeAlterInterceptors<T>();
|
|
||||||
ApplyFilters<T>();
|
ApplyFilters<T>();
|
||||||
|
return HasGrouping ? ExecuteGrouping<T>() : ExecuteNoGrouping<T>();
|
||||||
// create group levels.
|
|
||||||
if (Criteria.Groups.Count != 0)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual ConditionOperators? ResolveFromOrDefault(FilterType filterType) =>
|
protected virtual IQueryExecutionResult ExecuteGrouping<T>()
|
||||||
filterType.ConditionOperator();
|
|
||||||
|
|
||||||
protected virtual ConditionOperators ResolveFrom(FilterType filterType)
|
|
||||||
{
|
|
||||||
var ret = ResolveFromOrDefault(filterType);
|
|
||||||
if (ret == null)
|
|
||||||
throw new NotSupportedException($"{filterType} is not supported");
|
|
||||||
|
|
||||||
return ret.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void ApplyFilters<T>()
|
|
||||||
{
|
|
||||||
CurrentQueryable = CurrentQueryable.Query(whereBuilder =>
|
|
||||||
{
|
|
||||||
Criteria.Filters.ForEach(filter => ApplyFilter<T>(whereBuilder, filter));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void ApplyFilter<T>(WhereBuilder whereBuilder, IFilter filter)
|
|
||||||
{
|
|
||||||
var transformedFilter = InterceptFilter<T>(filter);
|
|
||||||
if (transformedFilter is ISimpleFilter)
|
|
||||||
ApplySimpleFilter<T>(whereBuilder, transformedFilter as ISimpleFilter);
|
|
||||||
else if (transformedFilter is ICompositeFilter)
|
|
||||||
AppleCompositeFilter<T>(whereBuilder, transformedFilter as ICompositeFilter);
|
|
||||||
else
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void AppleCompositeFilter<T>(WhereBuilder whereBuilder, ICompositeFilter filter)
|
|
||||||
{
|
|
||||||
whereBuilder.SubQuery(subWhereBuilder => filter.Filters.ForEach(subFilter => ApplyFilter<T>(subWhereBuilder, subFilter)), filter.And == true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void ApplySimpleFilter<T>(WhereBuilder whereBuilder, ISimpleFilter filter)
|
|
||||||
{
|
|
||||||
var resolvedConditionOperator = ResolveFrom(filter.Type);
|
|
||||||
whereBuilder.Compare(filter.Path, resolvedConditionOperator, filter.Value, and: filter.And == true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IFilter InterceptFilter<T>(IFilter filter)
|
|
||||||
{
|
|
||||||
var ret = Interceptors.Where(t => t is IFilterInterceptor)
|
|
||||||
.Cast<IFilterInterceptor>()
|
|
||||||
.Aggregate(filter, (previousFilter, interceptor) => interceptor.InterceptFilter(previousFilter));
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ApplyInterceptorsAndCriteria()
|
|
||||||
{
|
|
||||||
var genericMethod = ApplyInterceptorsAndCriteriaMethod.MakeGenericMethod(QueryableUnderlyingType);
|
|
||||||
genericMethod.Invoke(this, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void ApplyGenericBeforeAlterInterceptors<T>()
|
|
||||||
{
|
|
||||||
CurrentQueryable = Interceptors
|
|
||||||
.Where(t => t is IBeforeQueryAlteredInterceptor<T>)
|
|
||||||
.Cast<IBeforeQueryAlteredInterceptor<T>>()
|
|
||||||
.Aggregate((IQueryable<T>)CurrentQueryable, (prev, interceptor) => interceptor.InterceptQueryBeforeAltered(Criteria, prev));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void ApplySimpleBeforeAlterInterceptors()
|
|
||||||
{
|
|
||||||
CurrentQueryable = Interceptors
|
|
||||||
.Where(t => t is IBeforeQueryAlteredInterceptor)
|
|
||||||
.Cast<IBeforeQueryAlteredInterceptor>()
|
|
||||||
.Aggregate(CurrentQueryable, (prev, interceptor) => interceptor.InterceptQueryBeforeAltered(Criteria, prev));
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual IQueryResult Execute(IQueryable queryable, IQueryCriteria criteria)
|
|
||||||
{
|
|
||||||
Reset(queryable, criteria);
|
|
||||||
ApplyInterceptorsAndCriteria();
|
|
||||||
var debug = CurrentQueryable.ToObjectList();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public virtual Task<IQueryResult> ExecuteAsync(IQueryable queryable, IQueryCriteria criteria)
|
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual IQueryExecutionResult ExecuteNoGrouping<T>()
|
||||||
|
{
|
||||||
|
var result = new QueryExecutionResult();
|
||||||
|
|
||||||
|
// total records.
|
||||||
|
result.TotalRecords = CurrentQueryable.LongCount();
|
||||||
|
|
||||||
|
// sorts and paging.
|
||||||
|
ApplyNoGroupingSorts<T>();
|
||||||
|
ApplyNoGroupingPaging<T>();
|
||||||
|
|
||||||
|
// the data.
|
||||||
|
result.Data = CurrentQueryable.ToObjectList();
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IQueryExecutionResult Execute(IQueryable queryable, IQueryCriteria criteria)
|
||||||
|
{
|
||||||
|
Reset(queryable, criteria);
|
||||||
|
return ExecuteReflected();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
167
PoweredSoft.DynamicQuery/QueryHandlerBase.cs
Normal file
167
PoweredSoft.DynamicQuery/QueryHandlerBase.cs
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
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<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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void AddInterceptor(IQueryInterceptor interceptor)
|
||||||
|
{
|
||||||
|
if (interceptor == null) throw new ArgumentNullException("interceptor");
|
||||||
|
|
||||||
|
if (!Interceptors.Contains(interceptor))
|
||||||
|
Interceptors.Add(interceptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void ApplyNoGroupingPaging<T>()
|
||||||
|
{
|
||||||
|
if (!HasPaging)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var q = (IQueryable<T>) CurrentQueryable;
|
||||||
|
var skip = ((Criteria.Page ?? 1) - 1) * Criteria.PageSize.Value;
|
||||||
|
CurrentQueryable = q.Skip(skip).Take(Criteria.PageSize.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void ApplyNoGroupingSorts<T>()
|
||||||
|
{
|
||||||
|
if (Criteria.Sorts?.Any() != true)
|
||||||
|
{
|
||||||
|
ApplyNoSortInterceptor<T>();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Criteria.Sorts.ForEach(sort =>
|
||||||
|
{
|
||||||
|
var transformedSort = InterceptSort<T>(sort);
|
||||||
|
if (transformedSort.Count == 0)
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual List<ISort> InterceptSort<T>(ISort sort)
|
||||||
|
{
|
||||||
|
var ret = Interceptors
|
||||||
|
.Where(t => t is ISortInterceptor)
|
||||||
|
.Cast<ISortInterceptor>()
|
||||||
|
.SelectMany(interceptor => interceptor.InterceptSort(sort));
|
||||||
|
|
||||||
|
return ret.Distinct().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void ApplyNoSortInterceptor<T>()
|
||||||
|
{
|
||||||
|
CurrentQueryable = Interceptors.Where(t => t is INoSortInterceptor)
|
||||||
|
.Cast<INoSortInterceptor>()
|
||||||
|
.Aggregate(CurrentQueryable, (prev, interceptor) => interceptor.InterceptNoSort(prev));
|
||||||
|
|
||||||
|
CurrentQueryable = Interceptors.Where(t => t is INoSortInterceptor<T>)
|
||||||
|
.Cast<INoSortInterceptor<T>>()
|
||||||
|
.Aggregate((IQueryable<T>)CurrentQueryable, (prev, interceptor) => interceptor.InterceptNoSort(prev));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual ConditionOperators? ResolveFromOrDefault(FilterType filterType) => filterType.ConditionOperator();
|
||||||
|
|
||||||
|
protected virtual ConditionOperators ResolveFrom(FilterType filterType)
|
||||||
|
{
|
||||||
|
var ret = ResolveFromOrDefault(filterType);
|
||||||
|
if (ret == null)
|
||||||
|
throw new NotSupportedException($"{filterType} is not supported");
|
||||||
|
|
||||||
|
return ret.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void ApplyFilters<T>()
|
||||||
|
{
|
||||||
|
if (true != Criteria.Filters?.Any())
|
||||||
|
return;
|
||||||
|
|
||||||
|
CurrentQueryable = CurrentQueryable.Query(whereBuilder =>
|
||||||
|
{
|
||||||
|
Criteria.Filters.ForEach(filter => ApplyFilter<T>(whereBuilder, filter));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void ApplyFilter<T>(WhereBuilder whereBuilder, IFilter filter)
|
||||||
|
{
|
||||||
|
var transformedFilter = InterceptFilter<T>(filter);
|
||||||
|
if (transformedFilter is ISimpleFilter)
|
||||||
|
ApplySimpleFilter<T>(whereBuilder, transformedFilter as ISimpleFilter);
|
||||||
|
else if (transformedFilter is ICompositeFilter)
|
||||||
|
AppleCompositeFilter<T>(whereBuilder, transformedFilter as ICompositeFilter);
|
||||||
|
else
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void AppleCompositeFilter<T>(WhereBuilder whereBuilder, ICompositeFilter filter)
|
||||||
|
{
|
||||||
|
whereBuilder.SubQuery(subWhereBuilder => filter.Filters.ForEach(subFilter => ApplyFilter<T>(subWhereBuilder, subFilter)), filter.And == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void ApplySimpleFilter<T>(WhereBuilder whereBuilder, ISimpleFilter filter)
|
||||||
|
{
|
||||||
|
var resolvedConditionOperator = ResolveFrom(filter.Type);
|
||||||
|
whereBuilder.Compare(filter.Path, resolvedConditionOperator, filter.Value, and: filter.And == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual IFilter InterceptFilter<T>(IFilter filter)
|
||||||
|
{
|
||||||
|
var ret = Interceptors.Where(t => t is IFilterInterceptor)
|
||||||
|
.Cast<IFilterInterceptor>()
|
||||||
|
.Aggregate(filter, (previousFilter, interceptor) => interceptor.InterceptFilter(previousFilter));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void ApplyIncludeStrategyInterceptors<T>()
|
||||||
|
{
|
||||||
|
CurrentQueryable = Interceptors
|
||||||
|
.Where(t => t is IIncludeStrategyInterceptor)
|
||||||
|
.Cast<IIncludeStrategyInterceptor>()
|
||||||
|
.Aggregate(CurrentQueryable, (prev, interceptor) => interceptor.InterceptIncludeStrategy(Criteria, prev));
|
||||||
|
|
||||||
|
CurrentQueryable = Interceptors
|
||||||
|
.Where(t => t is IIncludeStrategyInterceptor<T>)
|
||||||
|
.Cast<IIncludeStrategyInterceptor<T>>()
|
||||||
|
.Aggregate((IQueryable<T>)CurrentQueryable, (prev, interceptor) => interceptor.InterceptIncludeStrategy(Criteria, prev));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void ApplyBeforeFilterInterceptors<T>()
|
||||||
|
{
|
||||||
|
CurrentQueryable = Interceptors
|
||||||
|
.Where(t => t is IBeforeQueryFilterInterceptor)
|
||||||
|
.Cast<IBeforeQueryFilterInterceptor>()
|
||||||
|
.Aggregate(CurrentQueryable, (prev, interceptor) => interceptor.InterceptBeforeFiltering(Criteria, prev));
|
||||||
|
|
||||||
|
CurrentQueryable = Interceptors
|
||||||
|
.Where(t => t is IBeforeQueryFilterInterceptor<T>)
|
||||||
|
.Cast<IBeforeQueryFilterInterceptor<T>>()
|
||||||
|
.Aggregate((IQueryable<T>)CurrentQueryable, (prev, interceptor) => interceptor.InterceptBeforeFiltering(Criteria, prev));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
PoweredSoft.DynamicQuery/QueryResult.cs
Normal file
50
PoweredSoft.DynamicQuery/QueryResult.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using PoweredSoft.DynamicQuery.Core;
|
||||||
|
|
||||||
|
namespace PoweredSoft.DynamicQuery
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an aggregate result.
|
||||||
|
/// </summary>
|
||||||
|
public class AggregateResult : IAggregateResult
|
||||||
|
{
|
||||||
|
public string Path { get; set; }
|
||||||
|
public AggregateType Type { get; set; }
|
||||||
|
public object Value { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// part of a result.
|
||||||
|
public abstract class QueryResult : IQueryResult
|
||||||
|
{
|
||||||
|
public List<IAggregateResult> Aggregates { get; set; }
|
||||||
|
public List<object> Data { get; set; }
|
||||||
|
|
||||||
|
public bool ShouldSerializeAggregates() => Aggregates != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// not grouped.
|
||||||
|
public class QueryExecutionResult : QueryResult, IQueryExecutionResult
|
||||||
|
{
|
||||||
|
public long TotalRecords { get; set; }
|
||||||
|
public long? NumberOfPages { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// grouped.
|
||||||
|
public class GroupQueryResult : QueryResult, IGroupQueryResult
|
||||||
|
{
|
||||||
|
public string GroupPath { get; set; }
|
||||||
|
public object GroupValue { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<IQueryResult> GroupItems => Data.Cast<IQueryResult>();
|
||||||
|
public bool ShouldSerializeGroupItems() => false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GroupedQueryExecutionResult : GroupQueryResult, IQueryExecutionResult
|
||||||
|
{
|
||||||
|
public long TotalRecords { get; set; }
|
||||||
|
public long? NumberOfPages { get; set; }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user