reusable methods for diff kind of calls.
This commit is contained in:
parent
cbfd55cf02
commit
aba20f04e2
@ -249,5 +249,83 @@ namespace PoweredSoft.DynamicLinq.Test
|
|||||||
CollectionAssert.AreEqual(expected.Titles as ICollection, titles);
|
CollectionAssert.AreEqual(expected.Titles as ICollection, titles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GroupByToListWithPath()
|
||||||
|
{
|
||||||
|
var limitResult = TestData.Posts.Where(t => t.Author != null);
|
||||||
|
|
||||||
|
var expected = limitResult.GroupBy(t => new
|
||||||
|
{
|
||||||
|
AuthorFirstName = t.Author.FirstName
|
||||||
|
})
|
||||||
|
.Select(t => new
|
||||||
|
{
|
||||||
|
Key = t.Key.AuthorFirstName,
|
||||||
|
Contents = t.Select(t2 => t2.Content).ToList()
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var actualQuery = limitResult
|
||||||
|
.GroupBy(t => t.Path("Author.FirstName", "AuthorFirstName"))
|
||||||
|
.Select(t =>
|
||||||
|
{
|
||||||
|
t.Key("Key", "AuthorFirstName");
|
||||||
|
t.ToList("Content", "Contents", SelectCollectionHandling.LeaveAsIs);
|
||||||
|
});
|
||||||
|
|
||||||
|
var actual = actualQuery.ToDynamicClassList();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected.Count, actual.Count);
|
||||||
|
for(var i = 0; i < expected.Count; i++)
|
||||||
|
{
|
||||||
|
var itExpected = expected[i];
|
||||||
|
var itActual = actual[i];
|
||||||
|
|
||||||
|
|
||||||
|
Assert.AreEqual(itExpected.Key, itActual.GetDynamicPropertyValue<string>("Key"));
|
||||||
|
CollectionAssert.AreEqual(itExpected.Contents, itActual.GetDynamicPropertyValue("Contents") as ICollection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GroupByToListWithPathWithNullChecking()
|
||||||
|
{
|
||||||
|
var limitResult = TestData.Authors;
|
||||||
|
|
||||||
|
var expected = limitResult.GroupBy(t => new
|
||||||
|
{
|
||||||
|
AuthorFirstName = t.FirstName
|
||||||
|
})
|
||||||
|
.Select(t => new
|
||||||
|
{
|
||||||
|
Key = t.Key.AuthorFirstName,
|
||||||
|
Contents = t.SelectMany(t2 => t2.Posts.Select(t3 => t3.Content)).ToList()
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var actualQuery = limitResult
|
||||||
|
.GroupBy(t => t.NullChecking().Path("FirstName", "AuthorFirstName"))
|
||||||
|
.Select(t =>
|
||||||
|
{
|
||||||
|
t.NullChecking();
|
||||||
|
t.Key("Key", "AuthorFirstName");
|
||||||
|
t.ToList("Posts.Content", "Contents", SelectCollectionHandling.Flatten);
|
||||||
|
});
|
||||||
|
|
||||||
|
var actual = actualQuery.ToDynamicClassList();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected.Count, actual.Count);
|
||||||
|
for (var i = 0; i < expected.Count; i++)
|
||||||
|
{
|
||||||
|
var itExpected = expected[i];
|
||||||
|
var itActual = actual[i];
|
||||||
|
|
||||||
|
|
||||||
|
Assert.AreEqual(itExpected.Key, itActual.GetDynamicPropertyValue<string>("Key"));
|
||||||
|
CollectionAssert.AreEqual(itExpected.Contents, itActual.GetDynamicPropertyValue("Contents") as ICollection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,11 @@ namespace PoweredSoft.DynamicLinq.Helpers
|
|||||||
{
|
{
|
||||||
if (selectType == SelectTypes.Key)
|
if (selectType == SelectTypes.Key)
|
||||||
{
|
{
|
||||||
return ResolvePathForExpression(parameter, path);
|
var parser = new ExpressionParser(parameter, path);
|
||||||
|
var resolver = new PathExpressionResolver(parser);
|
||||||
|
resolver.NullChecking = nullChecking;
|
||||||
|
resolver.Resolve();
|
||||||
|
return resolver.GetResultBodyExpression();
|
||||||
}
|
}
|
||||||
else if (selectType == SelectTypes.Count)
|
else if (selectType == SelectTypes.Count)
|
||||||
{
|
{
|
||||||
@ -157,76 +161,69 @@ namespace PoweredSoft.DynamicLinq.Helpers
|
|||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
else if (selectType == SelectTypes.Average)
|
else if (selectType == SelectTypes.Average)
|
||||||
{
|
return CreateGroupedAggregateExpression(parameter, path, "Average");
|
||||||
/// https://stackoverflow.com/questions/25482097/call-enumerable-average-via-expression
|
|
||||||
var notGroupedType = parameter.Type.GenericTypeArguments[1];
|
|
||||||
var innerParameter = Expression.Parameter(notGroupedType);
|
|
||||||
var innerMemberExpression = ResolvePathForExpression(innerParameter, path);
|
|
||||||
var innerMemberLambda = Expression.Lambda(innerMemberExpression, innerParameter);
|
|
||||||
var body = Expression.Call(typeof(Enumerable), "Average", new[] { notGroupedType }, parameter, innerMemberLambda);
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
else if (selectType == SelectTypes.Sum)
|
else if (selectType == SelectTypes.Sum)
|
||||||
{
|
return CreateGroupedAggregateExpression(parameter, path, "Sum");
|
||||||
var notGroupedType = parameter.Type.GenericTypeArguments[1];
|
|
||||||
var innerParameter = Expression.Parameter(notGroupedType);
|
|
||||||
var innerMemberExpression = ResolvePathForExpression(innerParameter, path);
|
|
||||||
var innerMemberLambda = Expression.Lambda(innerMemberExpression, innerParameter);
|
|
||||||
var body = Expression.Call(typeof(Enumerable), "Sum", new[] { notGroupedType }, parameter, innerMemberLambda);
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
else if (selectType == SelectTypes.Min)
|
else if (selectType == SelectTypes.Min)
|
||||||
{
|
return CreateGroupedAggregateExpression(parameter, path, "Min");
|
||||||
var notGroupedType = parameter.Type.GenericTypeArguments[1];
|
|
||||||
var innerParameter = Expression.Parameter(notGroupedType);
|
|
||||||
var innerMemberExpression = ResolvePathForExpression(innerParameter, path);
|
|
||||||
var innerMemberLambda = Expression.Lambda(innerMemberExpression, innerParameter);
|
|
||||||
var body = Expression.Call(typeof(Enumerable), "Min", new[] { notGroupedType }, parameter, innerMemberLambda);
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
else if (selectType == SelectTypes.Max)
|
else if (selectType == SelectTypes.Max)
|
||||||
{
|
return CreateGroupedAggregateExpression(parameter, path, "Max");
|
||||||
var notGroupedType = parameter.Type.GenericTypeArguments[1];
|
|
||||||
var innerParameter = Expression.Parameter(notGroupedType);
|
|
||||||
var innerMemberExpression = ResolvePathForExpression(innerParameter, path);
|
|
||||||
var innerMemberLambda = Expression.Lambda(innerMemberExpression, innerParameter);
|
|
||||||
var body = Expression.Call(typeof(Enumerable), "Max", new[] { notGroupedType }, parameter, innerMemberLambda);
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
else if (selectType == SelectTypes.ToList)
|
else if (selectType == SelectTypes.ToList)
|
||||||
{
|
return CreateGroupedPathExpressionWithMethod(parameter, path, selectCollectionHandling, nullChecking, "ToList");
|
||||||
var notGroupedType = parameter.Type.GenericTypeArguments[1];
|
|
||||||
var body = Expression.Call(typeof(Enumerable), "ToList", new[] { notGroupedType }, parameter);
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
else if (selectType == SelectTypes.First)
|
else if (selectType == SelectTypes.First)
|
||||||
{
|
return CreateGroupedPathExpressionWithMethod(parameter, path, selectCollectionHandling, nullChecking, "First");
|
||||||
var notGroupedType = parameter.Type.GenericTypeArguments[1];
|
|
||||||
var body = Expression.Call(typeof(Enumerable), "First", new[] { notGroupedType }, parameter);
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
else if (selectType == SelectTypes.Last)
|
else if (selectType == SelectTypes.Last)
|
||||||
{
|
return CreateGroupedPathExpressionWithMethod(parameter, path, selectCollectionHandling, nullChecking, "Last");
|
||||||
var notGroupedType = parameter.Type.GenericTypeArguments[1];
|
|
||||||
var body = Expression.Call(typeof(Enumerable), "Last", new[] { notGroupedType }, parameter);
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
else if (selectType == SelectTypes.FirstOrDefault)
|
else if (selectType == SelectTypes.FirstOrDefault)
|
||||||
{
|
return CreateGroupedPathExpressionWithMethod(parameter, path, selectCollectionHandling, nullChecking, "FirstOrDefault");
|
||||||
var notGroupedType = parameter.Type.GenericTypeArguments[1];
|
|
||||||
var body = Expression.Call(typeof(Enumerable), "FirstOrDefault", new[] { notGroupedType }, parameter);
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
else if (selectType == SelectTypes.LastOrDefault)
|
else if (selectType == SelectTypes.LastOrDefault)
|
||||||
{
|
return CreateGroupedPathExpressionWithMethod(parameter, path, selectCollectionHandling, nullChecking, "LastOrDefault");
|
||||||
var notGroupedType = parameter.Type.GenericTypeArguments[1];
|
|
||||||
var body = Expression.Call(typeof(Enumerable), "LastOrDefault", new[] { notGroupedType }, parameter);
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new NotSupportedException($"unkown select type {selectType}");
|
throw new NotSupportedException($"unkown select type {selectType}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Expression CreateGroupedAggregateExpression(ParameterExpression parameter, string path, string methodName)
|
||||||
|
{
|
||||||
|
/// https://stackoverflow.com/questions/25482097/call-enumerable-average-via-expression
|
||||||
|
var notGroupedType = parameter.Type.GenericTypeArguments[1];
|
||||||
|
var innerParameter = Expression.Parameter(notGroupedType);
|
||||||
|
var innerMemberExpression = ResolvePathForExpression(innerParameter, path);
|
||||||
|
var innerMemberLambda = Expression.Lambda(innerMemberExpression, innerParameter);
|
||||||
|
var body = Expression.Call(typeof(Enumerable), methodName, new[] { notGroupedType }, parameter, innerMemberLambda);
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Expression CreateGroupedPathExpressionWithMethod(ParameterExpression parameter, string path, SelectCollectionHandling selectCollectionHandling, bool nullChecking, string methodName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(path))
|
||||||
|
{
|
||||||
|
var notGroupedType = parameter.Type.GenericTypeArguments[1];
|
||||||
|
var body = Expression.Call(typeof(Enumerable), methodName, new[] { notGroupedType }, parameter);
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var notGroupedType = parameter.Type.GenericTypeArguments[1];
|
||||||
|
var innerParameter = Expression.Parameter(notGroupedType);
|
||||||
|
var parser = new ExpressionParser(innerParameter, path);
|
||||||
|
var resolver = new PathExpressionResolver(parser);
|
||||||
|
resolver.NullChecking = nullChecking;
|
||||||
|
resolver.Resolve();
|
||||||
|
var expression = resolver.Result;
|
||||||
|
var selectExpression = WrapIntoSelectFromGrouping(parameter, expression, selectCollectionHandling);
|
||||||
|
var body = CallMethodOnSelectExpression(methodName, selectExpression);
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Expression WrapIntoSelectFromGrouping(ParameterExpression parameter, Expression innerLambdaExpression, SelectCollectionHandling selectCollectionHandling)
|
||||||
|
{
|
||||||
|
var selectType = parameter.Type.GenericTypeArguments.Skip(1).First();
|
||||||
|
var innerSelectType = ((LambdaExpression)innerLambdaExpression).ReturnType;
|
||||||
|
var selectExpression = Expression.Call(typeof(Enumerable), "Select", new Type[] { selectType, innerSelectType }, parameter, innerLambdaExpression);
|
||||||
|
return selectExpression;
|
||||||
|
}
|
||||||
|
|
||||||
private static Expression CreateSelectExpression(IQueryable query, ParameterExpression parameter, SelectTypes selectType, string path, SelectCollectionHandling selectCollectionHandling, bool nullChecking)
|
private static Expression CreateSelectExpression(IQueryable query, ParameterExpression parameter, SelectTypes selectType, string path, SelectCollectionHandling selectCollectionHandling, bool nullChecking)
|
||||||
{
|
{
|
||||||
if (!IsGrouping(query))
|
if (!IsGrouping(query))
|
||||||
@ -277,6 +274,13 @@ namespace PoweredSoft.DynamicLinq.Helpers
|
|||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Expression CallMethodOnSelectExpression(string methodName, Expression selectExpression)
|
||||||
|
{
|
||||||
|
var notGroupedType = selectExpression.Type.GenericTypeArguments.First();
|
||||||
|
var body = Expression.Call(typeof(Enumerable), methodName, new[] { notGroupedType }, selectExpression) as Expression;
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
private static bool IsGrouping(IQueryable query)
|
private static bool IsGrouping(IQueryable query)
|
||||||
{
|
{
|
||||||
// TODO needs to be alot better than this, but it will do for now.
|
// TODO needs to be alot better than this, but it will do for now.
|
||||||
|
Loading…
Reference in New Issue
Block a user