From 8ca897b30427992b1cdb940fe7a37dd6f11d81e5 Mon Sep 17 00:00:00 2001 From: David Lebee Date: Fri, 19 Oct 2018 16:44:13 -0500 Subject: [PATCH] grouping is starting well :P --- PoweredSoft.DynamicQuery.Cli/Program.cs | 23 ++++++++--- .../AggregateType.cs | 3 +- .../ISortInterceptor.cs | 2 +- PoweredSoft.DynamicQuery/Aggregate.cs | 13 ++++++ .../Extensions/FilterTypeExtensions.cs | 14 +++++++ PoweredSoft.DynamicQuery/QueryHandler.cs | 28 ++++++++++++- PoweredSoft.DynamicQuery/QueryHandlerBase.cs | 40 ++++++++++++++++--- 7 files changed, 108 insertions(+), 15 deletions(-) create mode 100644 PoweredSoft.DynamicQuery/Aggregate.cs diff --git a/PoweredSoft.DynamicQuery.Cli/Program.cs b/PoweredSoft.DynamicQuery.Cli/Program.cs index 6b91df8..eeb12f0 100644 --- a/PoweredSoft.DynamicQuery.Cli/Program.cs +++ b/PoweredSoft.DynamicQuery.Cli/Program.cs @@ -47,6 +47,7 @@ namespace PoweredSoft.DynamicQuery.Cli public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } + public int Age { get; set; } } public class OtherClass @@ -67,11 +68,11 @@ namespace PoweredSoft.DynamicQuery.Cli { var list = new List() { - new Person{ Id = 1, FirstName = "David", LastName = "Lebee"}, - new Person{ Id = 2, FirstName = "Michaela", LastName = "Lebee"}, - new Person{ Id = 3, FirstName = "Zohra", LastName = "Lebee"}, - new Person{ Id = 4, FirstName = "Eric", LastName = "Vickar"}, - new Person{ Id = 5, FirstName = "Susan", LastName = "Vickar"}, + new Person{ Id = 1, FirstName = "David", LastName = "Lebee", Age = 29}, + new Person{ Id = 2, FirstName = "Michaela", LastName = "Lebee", Age = 29}, + new Person{ Id = 3, FirstName = "Zohra", LastName = "Lebee", Age = 20}, + new Person{ Id = 4, FirstName = "Eric", LastName = "Vickar", Age = 30}, + new Person{ Id = 5, FirstName = "Susan", LastName = "Vickar", Age = 30}, }; var queryable = list.AsQueryable(); @@ -79,6 +80,7 @@ namespace PoweredSoft.DynamicQuery.Cli criteria.Page = 1; criteria.PageSize = 10; + /* criteria.Filters = new List { new SimpleFilter() {Path = nameof(Person.LastName), Value = "Lebee", Type = FilterType.Equal}, @@ -92,8 +94,19 @@ namespace PoweredSoft.DynamicQuery.Cli new SimpleFilter() {Path = nameof(Person.FirstName), Value = "Zohra", Type = FilterType.Equal}, } } + };*/ + + criteria.Groups = new List() + { + new Group { Path = "LastName" } }; + criteria.Aggregates = new List() + { + new Aggregate { Path = "Age", Type = AggregateType.Count }, + new Aggregate { Path = "Age", Type = AggregateType.Avg } + };; + var handler = new QueryHandler(); handler.AddInterceptor(new PersonQueryInterceptor()); var result = handler.Execute(queryable, criteria); diff --git a/PoweredSoft.DynamicQuery.Core/AggregateType.cs b/PoweredSoft.DynamicQuery.Core/AggregateType.cs index fac51c7..4c796fc 100644 --- a/PoweredSoft.DynamicQuery.Core/AggregateType.cs +++ b/PoweredSoft.DynamicQuery.Core/AggregateType.cs @@ -5,7 +5,6 @@ Count, Sum, Avg, - Max, - Min + LongCount } } \ No newline at end of file diff --git a/PoweredSoft.DynamicQuery.Core/ISortInterceptor.cs b/PoweredSoft.DynamicQuery.Core/ISortInterceptor.cs index 211d122..001add4 100644 --- a/PoweredSoft.DynamicQuery.Core/ISortInterceptor.cs +++ b/PoweredSoft.DynamicQuery.Core/ISortInterceptor.cs @@ -4,6 +4,6 @@ namespace PoweredSoft.DynamicQuery.Core { public interface ISortInterceptor : IQueryInterceptor { - IEnumerable InterceptSort(ISort sort); + IEnumerable InterceptSort(IEnumerable sort); } } diff --git a/PoweredSoft.DynamicQuery/Aggregate.cs b/PoweredSoft.DynamicQuery/Aggregate.cs new file mode 100644 index 0000000..589c990 --- /dev/null +++ b/PoweredSoft.DynamicQuery/Aggregate.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; +using PoweredSoft.DynamicQuery.Core; + +namespace PoweredSoft.DynamicQuery +{ + public class Aggregate : IAggregate + { + public string Path { get; set; } + public AggregateType Type { get; set; } + } +} diff --git a/PoweredSoft.DynamicQuery/Extensions/FilterTypeExtensions.cs b/PoweredSoft.DynamicQuery/Extensions/FilterTypeExtensions.cs index c122eff..56f4b09 100644 --- a/PoweredSoft.DynamicQuery/Extensions/FilterTypeExtensions.cs +++ b/PoweredSoft.DynamicQuery/Extensions/FilterTypeExtensions.cs @@ -35,5 +35,19 @@ namespace PoweredSoft.DynamicQuery.Extensions return null; } + + public static SelectTypes? SelectType(this AggregateType aggregateType) + { + if (aggregateType == AggregateType.Avg) + return SelectTypes.Average; + if (aggregateType == AggregateType.Count) + return SelectTypes.Count; + if (aggregateType == AggregateType.LongCount) + return SelectTypes.LongCount; + if (aggregateType == AggregateType.Sum) + return SelectTypes.Sum; + + return null; + } } } diff --git a/PoweredSoft.DynamicQuery/QueryHandler.cs b/PoweredSoft.DynamicQuery/QueryHandler.cs index 8078891..8473e71 100644 --- a/PoweredSoft.DynamicQuery/QueryHandler.cs +++ b/PoweredSoft.DynamicQuery/QueryHandler.cs @@ -23,9 +23,35 @@ namespace PoweredSoft.DynamicQuery protected virtual IQueryExecutionResult ExecuteGrouping() { - throw new NotImplementedException(); + var result = new GroupedQueryExecutionResult(); + result.TotalRecords = CurrentQueryable.LongCount(); + + Criteria.Groups.ForEach(group => + { + var finalGroup = InterceptGroup(group); + var groupCleanedPath = group.Path.Replace(".", ""); + CurrentQueryable = CurrentQueryable.GroupBy(QueryableUnderlyingType, gb => + { + gb.Path(finalGroup.Path); + }); + + CurrentQueryable = CurrentQueryable.Select(sb => + { + sb.ToList("Data"); + sb.Key($"Group_{groupCleanedPath}", group.Path); + Criteria.Aggregates.ForEach(a => + { + var selectType = ResolveSelectFrom(a.Type); + var pathCleaned = a.Path.Replace(".", ""); + sb.Aggregate(a.Path, selectType, $"Agg_{a.Type}_{pathCleaned}"); + }); + }); + }); + + return result; } + protected virtual IQueryExecutionResult ExecuteNoGrouping() { var result = new QueryExecutionResult(); diff --git a/PoweredSoft.DynamicQuery/QueryHandlerBase.cs b/PoweredSoft.DynamicQuery/QueryHandlerBase.cs index d01d420..4a19955 100644 --- a/PoweredSoft.DynamicQuery/QueryHandlerBase.cs +++ b/PoweredSoft.DynamicQuery/QueryHandlerBase.cs @@ -38,6 +38,17 @@ namespace PoweredSoft.DynamicQuery 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) @@ -66,12 +77,18 @@ namespace PoweredSoft.DynamicQuery protected virtual List InterceptSort(ISort sort) { + var original = new List() + { + sort + }; + var ret = Interceptors .Where(t => t is ISortInterceptor) .Cast() - .SelectMany(interceptor => interceptor.InterceptSort(sort)); + .Aggregate(original as IEnumerable, (prev, inter) => inter.InterceptSort(prev)) + .Distinct(); - return ret.Distinct().ToList(); + return ret.ToList(); } protected virtual void ApplyNoSortInterceptor() @@ -85,17 +102,28 @@ namespace PoweredSoft.DynamicQuery .Aggregate((IQueryable)CurrentQueryable, (prev, interceptor) => interceptor.InterceptNoSort(prev)); } - protected virtual ConditionOperators? ResolveFromOrDefault(FilterType filterType) => filterType.ConditionOperator(); - protected virtual ConditionOperators ResolveFrom(FilterType filterType) + protected virtual SelectTypes? ResolveSelectFromOrDefault(AggregateType aggregateType) => aggregateType.SelectType(); + protected virtual ConditionOperators? ResolveConditionOperatorFromOrDefault(FilterType filterType) => filterType.ConditionOperator(); + + protected virtual ConditionOperators ResolveConditionOperatorFrom(FilterType filterType) { - var ret = ResolveFromOrDefault(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()) @@ -125,7 +153,7 @@ namespace PoweredSoft.DynamicQuery protected virtual void ApplySimpleFilter(WhereBuilder whereBuilder, ISimpleFilter filter) { - var resolvedConditionOperator = ResolveFrom(filter.Type); + var resolvedConditionOperator = ResolveConditionOperatorFrom(filter.Type); whereBuilder.Compare(filter.Path, resolvedConditionOperator, filter.Value, and: filter.And == true); }