added feature for batch readings alterations.
This commit is contained in:
parent
9b51e2e287
commit
61642eee18
27
PoweredSoft.DynamicQuery.Core/IAfterReadInterceptor.cs
Normal file
27
PoweredSoft.DynamicQuery.Core/IAfterReadInterceptor.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PoweredSoft.DynamicQuery.Core
|
||||
{
|
||||
public interface IAfterReadEntityInterceptor<T> : IQueryInterceptor
|
||||
{
|
||||
void AfterReadEntity(List<T> entities);
|
||||
}
|
||||
|
||||
public interface IAfterReadEntityInterceptorAsync<T> : IQueryInterceptor
|
||||
{
|
||||
Task AfterReadEntityAsync(List<T> entities, CancellationToken cancellationToken = default(CancellationToken));
|
||||
}
|
||||
|
||||
public interface IAfterReadInterceptor<T> : IQueryInterceptor
|
||||
{
|
||||
void AfterRead(List<Tuple<T, object>> pairs);
|
||||
}
|
||||
|
||||
public interface IAfterReadInterceptorAsync<T> : IQueryInterceptor
|
||||
{
|
||||
Task AfterReadAsync(List<Tuple<T, object>> pairs, CancellationToken cancellationToken = default(CancellationToken));
|
||||
}
|
||||
}
|
@ -1,4 +1,8 @@
|
||||
namespace PoweredSoft.DynamicQuery.Core
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PoweredSoft.DynamicQuery.Core
|
||||
{
|
||||
public interface IQueryConvertInterceptor : IQueryInterceptor
|
||||
{
|
||||
|
@ -4,6 +4,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace PoweredSoft.DynamicQuery.Test
|
||||
@ -35,7 +37,7 @@ namespace PoweredSoft.DynamicQuery.Test
|
||||
|
||||
// top level should have same amount of group levels.
|
||||
Assert.Equal(result.Data.Count, shouldResult.Count);
|
||||
for(var i = 0; i < shouldResult.Count; i++)
|
||||
for (var i = 0; i < shouldResult.Count; i++)
|
||||
{
|
||||
var expected = shouldResult[0];
|
||||
var actual = ((IGroupQueryResult)result.Data[0]);
|
||||
@ -79,5 +81,82 @@ namespace PoweredSoft.DynamicQuery.Test
|
||||
Assert.Equal(expected, c);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InterceptorsWithGrouping()
|
||||
{
|
||||
MockContextFactory.SeedAndTestContextFor("GroupTests_InterceptorsWithGrouping", TestSeeders.SeedTicketScenario, ctx =>
|
||||
{
|
||||
var criteria = new QueryCriteria()
|
||||
{
|
||||
Groups = new List<IGroup>()
|
||||
{
|
||||
new Group { Path = "TicketType" }
|
||||
},
|
||||
Aggregates = new List<IAggregate>()
|
||||
{
|
||||
new Aggregate { Type = AggregateType.Count }
|
||||
}
|
||||
};
|
||||
|
||||
var interceptor = new InterceptorsWithGrouping();
|
||||
var queryHandler = new QueryHandler();
|
||||
queryHandler.AddInterceptor(interceptor);
|
||||
var result = queryHandler.Execute(ctx.Tickets, criteria);
|
||||
Assert.Equal(4, interceptor.Count);
|
||||
Assert.True(interceptor.Test);
|
||||
Assert.True(interceptor.Test2);
|
||||
Assert.True(interceptor.Test3);
|
||||
Assert.True(interceptor.Test4);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class InterceptorWithGroupingFakeModel
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
class InterceptorsWithGrouping :
|
||||
IAfterReadEntityInterceptor<Ticket>,
|
||||
IAfterReadEntityInterceptorAsync<Ticket>,
|
||||
IAfterReadInterceptor<Ticket>,
|
||||
IAfterReadInterceptorAsync<Ticket>,
|
||||
IQueryConvertInterceptor<Ticket>
|
||||
{
|
||||
public int Count { get; set; } = 0;
|
||||
public bool Test { get; set; } = false;
|
||||
public bool Test2 { get; set; } = false;
|
||||
public bool Test3 { get; set; } = false;
|
||||
public bool Test4 { get; set; } = false;
|
||||
|
||||
public void AfterRead(List<Tuple<Ticket, object>> pairs)
|
||||
{
|
||||
Test = true;
|
||||
Count++;
|
||||
}
|
||||
|
||||
public async Task AfterReadAsync(List<Tuple<Ticket, object>> pairs, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
Test2 = true;
|
||||
Count++;
|
||||
}
|
||||
|
||||
public void AfterReadEntity(List<Ticket> entities)
|
||||
{
|
||||
Test3 = true;
|
||||
Count++;
|
||||
}
|
||||
|
||||
public async Task AfterReadEntityAsync(List<Ticket> entities, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
Test4 = true;
|
||||
Count++;
|
||||
}
|
||||
|
||||
public object InterceptResultTo(Ticket entity)
|
||||
{
|
||||
return new InterceptorWithGroupingFakeModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using PoweredSoft.DynamicLinq;
|
||||
using PoweredSoft.DynamicLinq.Fluent;
|
||||
using PoweredSoft.DynamicQuery.Core;
|
||||
@ -57,13 +58,15 @@ namespace PoweredSoft.DynamicQuery
|
||||
var groupRecords = CurrentQueryable.ToDynamicClassList();
|
||||
|
||||
// now join them into logical collections
|
||||
result.Data = RecursiveRegroup<T>(groupRecords, aggregateResults, Criteria.Groups.First());
|
||||
var lastLists = new List<List<object>>();
|
||||
result.Data = RecursiveRegroup<T>(groupRecords, aggregateResults, Criteria.Groups.First(), lastLists);
|
||||
|
||||
// intercept grouped by.
|
||||
QueryInterceptToGrouped<T>(lastLists).Wait();
|
||||
|
||||
result.Aggregates = CalculateTotalAggregate<T>(queryableAfterFilters);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
protected virtual List<IAggregateResult> CalculateTotalAggregate<T>(IQueryable queryableAfterFilters)
|
||||
{
|
||||
if (!Criteria.Aggregates.Any())
|
||||
@ -107,7 +110,7 @@ namespace PoweredSoft.DynamicQuery
|
||||
|
||||
// data.
|
||||
var entities = ((IQueryable<T>)CurrentQueryable).ToList();
|
||||
var records = InterceptConvertTo<T>(entities);
|
||||
var records = InterceptConvertTo<T>(entities).Result;
|
||||
result.Data = records;
|
||||
|
||||
// aggregates.
|
||||
|
@ -70,7 +70,11 @@ namespace PoweredSoft.DynamicQuery
|
||||
var groupRecords = await AsyncQueryableService.ToListAsync(CurrentQueryable.Cast<DynamicClass>(), cancellationToken);
|
||||
|
||||
// now join them into logical collections
|
||||
result.Data = RecursiveRegroup<T>(groupRecords, aggregateResults, Criteria.Groups.First());
|
||||
var lastLists = new List<List<object>>();
|
||||
result.Data = RecursiveRegroup<T>(groupRecords, aggregateResults, Criteria.Groups.First(), lastLists);
|
||||
|
||||
// converted to grouped by.
|
||||
await QueryInterceptToGrouped<T>(lastLists);
|
||||
|
||||
result.Aggregates = await CalculateTotalAggregateAsync<T>(queryableAfterFilters, cancellationToken);
|
||||
return result;
|
||||
@ -93,7 +97,7 @@ namespace PoweredSoft.DynamicQuery
|
||||
|
||||
// data.
|
||||
var entities = await AsyncQueryableService.ToListAsync(((IQueryable<T>)CurrentQueryable), cancellationToken);
|
||||
var records = InterceptConvertTo<T>(entities);
|
||||
var records = await InterceptConvertTo<T>(entities);
|
||||
result.Data = records;
|
||||
|
||||
// aggregates.
|
||||
|
@ -182,15 +182,46 @@ namespace PoweredSoft.DynamicQuery
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected virtual List<object> InterceptConvertTo<T>(List<T> entities)
|
||||
protected virtual async Task<List<object>> InterceptConvertTo<T>(List<T> entities)
|
||||
{
|
||||
await AfterEntityReadInterceptors(entities);
|
||||
|
||||
var objects = entities.Cast<object>().ToList();
|
||||
for (var i = 0; i < objects.Count; i++)
|
||||
objects[i] = InterceptConvertToObject<T>(objects[i]);
|
||||
|
||||
var pairs = entities.Select((t, index) => Tuple.Create(t, objects[index])).ToList();
|
||||
await AfterReadInterceptors<T>(pairs);
|
||||
|
||||
return objects;
|
||||
}
|
||||
|
||||
protected virtual async Task AfterEntityReadInterceptors<T>(List<T> entities)
|
||||
{
|
||||
Interceptors
|
||||
.Where(t => t is IAfterReadEntityInterceptor<T>)
|
||||
.Cast<IAfterReadEntityInterceptor<T>>()
|
||||
.ToList()
|
||||
.ForEach(t => t.AfterReadEntity(entities));
|
||||
|
||||
var asyncInterceptors = Interceptors.Where(t => t is IAfterReadEntityInterceptorAsync<T>).Cast<IAfterReadEntityInterceptorAsync<T>>();
|
||||
foreach (var interceptor in asyncInterceptors)
|
||||
await interceptor.AfterReadEntityAsync(entities);
|
||||
}
|
||||
|
||||
protected virtual async Task AfterReadInterceptors<T>(List<Tuple<T, object>> pairs)
|
||||
{
|
||||
Interceptors
|
||||
.Where(t => t is IAfterReadInterceptor<T>)
|
||||
.Cast<IAfterReadInterceptor<T>>()
|
||||
.ToList()
|
||||
.ForEach(t => t.AfterRead(pairs));
|
||||
|
||||
var asyncInterceptors = Interceptors.Where(t => t is IAfterReadInterceptorAsync<T>).Cast<IAfterReadInterceptorAsync<T>>();
|
||||
foreach (var interceptor in asyncInterceptors)
|
||||
await interceptor.AfterReadAsync(pairs);
|
||||
}
|
||||
|
||||
protected virtual object InterceptConvertToObject<T>(object o)
|
||||
{
|
||||
o = Interceptors
|
||||
@ -329,7 +360,7 @@ namespace PoweredSoft.DynamicQuery
|
||||
.Aggregate((IQueryable<T>)CurrentQueryable, (prev, interceptor) => interceptor.InterceptBeforeFiltering(Criteria, prev));
|
||||
}
|
||||
|
||||
protected virtual List<object> RecursiveRegroup<T>(List<DynamicClass> groupRecords, List<List<DynamicClass>> aggregateResults, IGroup group, List<IGroupQueryResult> parentGroupResults = null)
|
||||
protected virtual List<object> RecursiveRegroup<T>(List<DynamicClass> groupRecords, List<List<DynamicClass>> aggregateResults, IGroup group, List<List<object>> lastLists, List<IGroupQueryResult> parentGroupResults = null)
|
||||
{
|
||||
var groupIndex = Criteria.Groups.IndexOf(group);
|
||||
var isLast = Criteria.Groups.Last() == group;
|
||||
@ -376,11 +407,12 @@ namespace PoweredSoft.DynamicQuery
|
||||
if (isLast)
|
||||
{
|
||||
var entities = t.SelectMany(t2 => t2.GetDynamicPropertyValue<List<T>>("Records")).ToList();
|
||||
groupResult.Data = InterceptConvertTo<T>(entities);
|
||||
groupResult.Data = entities.Cast<object>().ToList();
|
||||
lastLists.Add(groupResult.Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
groupResult.Data = RecursiveRegroup<T>(t.ToList(), aggregateResults, Criteria.Groups[groupIndex + 1], groupResults);
|
||||
groupResult.Data = RecursiveRegroup<T>(t.ToList(), aggregateResults, Criteria.Groups[groupIndex + 1], lastLists, groupResults);
|
||||
}
|
||||
|
||||
return groupResult;
|
||||
@ -389,5 +421,26 @@ namespace PoweredSoft.DynamicQuery
|
||||
.ToList();
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected virtual async Task QueryInterceptToGrouped<T>(List<List<object>> lists)
|
||||
{
|
||||
var entities = lists.SelectMany(t => t).Cast<T>().ToList();
|
||||
await AfterEntityReadInterceptors(entities);
|
||||
|
||||
var pairs = new List<Tuple<T, object>>();
|
||||
|
||||
lists.ForEach(innerList =>
|
||||
{
|
||||
for(var i = 0; i < innerList.Count; i++)
|
||||
{
|
||||
var entity = (T)innerList[i];
|
||||
var convertedObject = InterceptConvertToObject<T>(entity);
|
||||
innerList[i] = convertedObject;
|
||||
pairs.Add(Tuple.Create(entity, convertedObject));
|
||||
}
|
||||
});
|
||||
|
||||
await AfterReadInterceptors<T>(pairs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user