reusable methods for diff kind of calls.

This commit is contained in:
David Lebee 2018-10-26 15:54:05 -05:00
parent cbfd55cf02
commit aba20f04e2
2 changed files with 141 additions and 59 deletions

View File

@ -249,5 +249,83 @@ namespace PoweredSoft.DynamicLinq.Test
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);
}
}
}
}

View File

@ -142,7 +142,11 @@ namespace PoweredSoft.DynamicLinq.Helpers
{
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)
{
@ -157,76 +161,69 @@ namespace PoweredSoft.DynamicLinq.Helpers
return body;
}
else if (selectType == SelectTypes.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;
}
return CreateGroupedAggregateExpression(parameter, path, "Average");
else if (selectType == SelectTypes.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;
}
return CreateGroupedAggregateExpression(parameter, path, "Sum");
else if (selectType == SelectTypes.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;
}
return CreateGroupedAggregateExpression(parameter, path, "Min");
else if (selectType == SelectTypes.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;
}
return CreateGroupedAggregateExpression(parameter, path, "Max");
else if (selectType == SelectTypes.ToList)
{
var notGroupedType = parameter.Type.GenericTypeArguments[1];
var body = Expression.Call(typeof(Enumerable), "ToList", new[] { notGroupedType }, parameter);
return body;
}
return CreateGroupedPathExpressionWithMethod(parameter, path, selectCollectionHandling, nullChecking, "ToList");
else if (selectType == SelectTypes.First)
{
var notGroupedType = parameter.Type.GenericTypeArguments[1];
var body = Expression.Call(typeof(Enumerable), "First", new[] { notGroupedType }, parameter);
return body;
}
return CreateGroupedPathExpressionWithMethod(parameter, path, selectCollectionHandling, nullChecking, "First");
else if (selectType == SelectTypes.Last)
{
var notGroupedType = parameter.Type.GenericTypeArguments[1];
var body = Expression.Call(typeof(Enumerable), "Last", new[] { notGroupedType }, parameter);
return body;
}
return CreateGroupedPathExpressionWithMethod(parameter, path, selectCollectionHandling, nullChecking, "Last");
else if (selectType == SelectTypes.FirstOrDefault)
{
var notGroupedType = parameter.Type.GenericTypeArguments[1];
var body = Expression.Call(typeof(Enumerable), "FirstOrDefault", new[] { notGroupedType }, parameter);
return body;
}
return CreateGroupedPathExpressionWithMethod(parameter, path, selectCollectionHandling, nullChecking, "FirstOrDefault");
else if (selectType == SelectTypes.LastOrDefault)
{
var notGroupedType = parameter.Type.GenericTypeArguments[1];
var body = Expression.Call(typeof(Enumerable), "LastOrDefault", new[] { notGroupedType }, parameter);
return body;
}
return CreateGroupedPathExpressionWithMethod(parameter, path, selectCollectionHandling, nullChecking, "LastOrDefault");
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)
{
if (!IsGrouping(query))
@ -277,6 +274,13 @@ namespace PoweredSoft.DynamicLinq.Helpers
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)
{
// TODO needs to be alot better than this, but it will do for now.