select works just need to add null checks.
This commit is contained in:
parent
57fbee664e
commit
8f35c2a377
@ -14,15 +14,19 @@ namespace PoweredSoft.DynamicLinq.Test
|
|||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestSelect()
|
public void TestSelect()
|
||||||
{
|
{
|
||||||
var regularSyntax = TestData.Authors
|
var regularSyntaxA = TestData.Authors
|
||||||
.AsQueryable()
|
.AsQueryable()
|
||||||
.Select(t => new
|
.Select(t => new
|
||||||
{
|
{
|
||||||
Id = t.Id,
|
Id = t.Id,
|
||||||
AuthorFirstName = t.FirstName,
|
AuthorFirstName = t.FirstName,
|
||||||
AuthorLastName = t.LastName,
|
AuthorLastName = t.LastName,
|
||||||
Posts = t.Posts.ToList()
|
Posts = t.Posts.ToList(),
|
||||||
}).ToList();
|
Comments = t.Posts.Select(t2 => t2.Comments).ToList(),
|
||||||
|
Comments2 = t.Posts.SelectMany(t2 => t2.Comments).ToList()
|
||||||
|
});
|
||||||
|
|
||||||
|
//var regularSyntax = regularSyntaxA.ToList();
|
||||||
|
|
||||||
var dynamicSyntax = TestData.Authors
|
var dynamicSyntax = TestData.Authors
|
||||||
.AsQueryable()
|
.AsQueryable()
|
||||||
@ -32,8 +36,12 @@ namespace PoweredSoft.DynamicLinq.Test
|
|||||||
t.Path("FirstName", "AuthorFirstName");
|
t.Path("FirstName", "AuthorFirstName");
|
||||||
t.Path("LastName", "AuthorLastName");
|
t.Path("LastName", "AuthorLastName");
|
||||||
t.PathToList("Posts");
|
t.PathToList("Posts");
|
||||||
}).ToDynamicClassList();
|
t.PathToList("Posts.Comments");
|
||||||
|
t.PathToList("Posts.Comments", "Comments2", SelectCollectionHandling.SelectMany);
|
||||||
|
})
|
||||||
|
.ToDynamicClassList();
|
||||||
|
|
||||||
|
/*
|
||||||
Assert.AreEqual(regularSyntax.Count, dynamicSyntax.Count);
|
Assert.AreEqual(regularSyntax.Count, dynamicSyntax.Count);
|
||||||
for(var i = 0; i < regularSyntax.Count; i++)
|
for(var i = 0; i < regularSyntax.Count; i++)
|
||||||
{
|
{
|
||||||
@ -41,7 +49,15 @@ namespace PoweredSoft.DynamicLinq.Test
|
|||||||
Assert.AreEqual(regularSyntax[i].AuthorFirstName, dynamicSyntax[i].GetDynamicPropertyValue<string>("AuthorFirstName"));
|
Assert.AreEqual(regularSyntax[i].AuthorFirstName, dynamicSyntax[i].GetDynamicPropertyValue<string>("AuthorFirstName"));
|
||||||
Assert.AreEqual(regularSyntax[i].AuthorLastName, dynamicSyntax[i].GetDynamicPropertyValue<string>("AuthorLastName"));
|
Assert.AreEqual(regularSyntax[i].AuthorLastName, dynamicSyntax[i].GetDynamicPropertyValue<string>("AuthorLastName"));
|
||||||
Helpers.QueryableAssert.AreEqual(regularSyntax[i].Posts.AsQueryable(), dynamicSyntax[i].GetDynamicPropertyValue<List<Post>>("Posts").AsQueryable());
|
Helpers.QueryableAssert.AreEqual(regularSyntax[i].Posts.AsQueryable(), dynamicSyntax[i].GetDynamicPropertyValue<List<Post>>("Posts").AsQueryable());
|
||||||
}
|
//Helpers.QueryableAssert.AreEqual(regularSyntax[i].Comments.AsQueryable(), dynamicSyntax[i].GetDynamicPropertyValue<List<Comment>>("Comments").AsQueryable());
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SelectNullChecking()
|
||||||
|
{
|
||||||
|
// TODO: null checking in select operations :D
|
||||||
|
throw new Exception("TODO");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,12 @@ namespace PoweredSoft.DynamicLinq
|
|||||||
Path
|
Path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum SelectCollectionHandling
|
||||||
|
{
|
||||||
|
Select,
|
||||||
|
SelectMany
|
||||||
|
}
|
||||||
|
|
||||||
internal static class Constants
|
internal static class Constants
|
||||||
{
|
{
|
||||||
internal static readonly MethodInfo GroupByMethod = typeof(Queryable).GetMethods().First(t => t.Name == "GroupBy");
|
internal static readonly MethodInfo GroupByMethod = typeof(Queryable).GetMethods().First(t => t.Name == "GroupBy");
|
||||||
|
@ -11,6 +11,7 @@ namespace PoweredSoft.DynamicLinq.Fluent
|
|||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
public string PropertyName { get; set; }
|
public string PropertyName { get; set; }
|
||||||
public SelectTypes SelectType { get; set; }
|
public SelectTypes SelectType { get; set; }
|
||||||
|
public SelectCollectionHandling SelectCollectionHandling { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SelectBuilder : IQueryBuilder
|
public class SelectBuilder : IQueryBuilder
|
||||||
@ -133,7 +134,7 @@ namespace PoweredSoft.DynamicLinq.Fluent
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SelectBuilder PathToList(string path, string propertyName = null)
|
public SelectBuilder PathToList(string path, string propertyName = null, SelectCollectionHandling selectCollectionHandling = SelectCollectionHandling.Select)
|
||||||
{
|
{
|
||||||
if (propertyName == null)
|
if (propertyName == null)
|
||||||
propertyName = path.Split('.').LastOrDefault();
|
propertyName = path.Split('.').LastOrDefault();
|
||||||
@ -144,7 +145,8 @@ namespace PoweredSoft.DynamicLinq.Fluent
|
|||||||
{
|
{
|
||||||
Path = path,
|
Path = path,
|
||||||
PropertyName = propertyName,
|
PropertyName = propertyName,
|
||||||
SelectType = SelectTypes.PathToList
|
SelectType = SelectTypes.PathToList,
|
||||||
|
SelectCollectionHandling = selectCollectionHandling
|
||||||
});
|
});
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@ -155,7 +157,7 @@ namespace PoweredSoft.DynamicLinq.Fluent
|
|||||||
if (Empty)
|
if (Empty)
|
||||||
throw new Exception("No select specified, please specify at least one select path");
|
throw new Exception("No select specified, please specify at least one select path");
|
||||||
|
|
||||||
var partsTuple = Parts.Select(t => (selectType: t.SelectType, propertyName: t.PropertyName, path: t.Path)).ToList();
|
var partsTuple = Parts.Select(t => (selectType: t.SelectType, propertyName: t.PropertyName, path: t.Path, selectCollectionHandling: t.SelectCollectionHandling)).ToList();
|
||||||
return QueryableHelpers.Select(Query, partsTuple, DestinationType);
|
return QueryableHelpers.Select(Query, partsTuple, DestinationType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,7 @@ namespace PoweredSoft.DynamicLinq.Helpers
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IQueryable Select(IQueryable query, List<(SelectTypes selectType, string propertyName, string path)> parts, Type destinationType = null)
|
public static IQueryable Select(IQueryable query, List<(SelectTypes selectType, string propertyName, string path, SelectCollectionHandling selectCollectionHandling)> parts, Type destinationType = null)
|
||||||
{
|
{
|
||||||
// create parameter.
|
// create parameter.
|
||||||
var queryType = query.ElementType;
|
var queryType = query.ElementType;
|
||||||
@ -129,7 +129,7 @@ namespace PoweredSoft.DynamicLinq.Helpers
|
|||||||
var partExpressions = new List<(Expression expression, string propertyName)>();
|
var partExpressions = new List<(Expression expression, string propertyName)>();
|
||||||
parts.ForEach(part =>
|
parts.ForEach(part =>
|
||||||
{
|
{
|
||||||
var partBodyExpression = CreateSelectExpression(query, parameter, part.selectType, part.path);
|
var partBodyExpression = CreateSelectExpression(query, parameter, part.selectType, part.path, part.selectCollectionHandling);
|
||||||
fields.Add((partBodyExpression.Type, part.propertyName));
|
fields.Add((partBodyExpression.Type, part.propertyName));
|
||||||
partExpressions.Add((partBodyExpression, part.propertyName));
|
partExpressions.Add((partBodyExpression, part.propertyName));
|
||||||
});
|
});
|
||||||
@ -146,11 +146,11 @@ namespace PoweredSoft.DynamicLinq.Helpers
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Expression CreateSelectExpressionForGrouping(IQueryable query, ParameterExpression parameter, SelectTypes selectType, string path)
|
private static Expression CreateSelectExpressionForGrouping(IQueryable query, ParameterExpression parameter, SelectTypes selectType, string path, SelectCollectionHandling selectCollectionHandling)
|
||||||
{
|
{
|
||||||
if (selectType == SelectTypes.Key)
|
if (selectType == SelectTypes.Key)
|
||||||
{
|
{
|
||||||
return ResolvePathForExpression(parameter, path);
|
return ResolvePathForExpression(parameter, path, selectCollectionHandling);
|
||||||
}
|
}
|
||||||
else if (selectType == SelectTypes.Count)
|
else if (selectType == SelectTypes.Count)
|
||||||
{
|
{
|
||||||
@ -193,23 +193,23 @@ namespace PoweredSoft.DynamicLinq.Helpers
|
|||||||
throw new NotSupportedException($"unkown select type {selectType}");
|
throw new NotSupportedException($"unkown select type {selectType}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Expression CreateSelectExpression(IQueryable query, ParameterExpression parameter, SelectTypes selectType, string path)
|
private static Expression CreateSelectExpression(IQueryable query, ParameterExpression parameter, SelectTypes selectType, string path, SelectCollectionHandling selectCollectionHandling)
|
||||||
{
|
{
|
||||||
if (!IsGrouping(query))
|
if (!IsGrouping(query))
|
||||||
return CreateSelectExpressionRegular(query, parameter, selectType, path);
|
return CreateSelectExpressionRegular(query, parameter, selectType, path, selectCollectionHandling);
|
||||||
|
|
||||||
return CreateSelectExpressionForGrouping(query, parameter, selectType, path);
|
return CreateSelectExpressionForGrouping(query, parameter, selectType, path, selectCollectionHandling);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Expression CreateSelectExpressionRegular(IQueryable query, ParameterExpression parameter, SelectTypes selectType, string path)
|
private static Expression CreateSelectExpressionRegular(IQueryable query, ParameterExpression parameter, SelectTypes selectType, string path, SelectCollectionHandling selectCollectionHandling)
|
||||||
{
|
{
|
||||||
if (selectType == SelectTypes.Path)
|
if (selectType == SelectTypes.Path)
|
||||||
{
|
{
|
||||||
return ResolvePathForExpression(parameter, path);
|
return ResolvePathForExpression(parameter, path, selectCollectionHandling);
|
||||||
}
|
}
|
||||||
else if (selectType == SelectTypes.PathToList)
|
else if (selectType == SelectTypes.PathToList)
|
||||||
{
|
{
|
||||||
var expr = ResolvePathForExpression(parameter, path);
|
var expr = ResolvePathForExpression(parameter, path, selectCollectionHandling);
|
||||||
var notGroupedType = expr.Type.GenericTypeArguments.FirstOrDefault();
|
var notGroupedType = expr.Type.GenericTypeArguments.FirstOrDefault();
|
||||||
if (notGroupedType == null)
|
if (notGroupedType == null)
|
||||||
throw new Exception($"Path must be a Enumerable<T> but its a {expr.Type}");
|
throw new Exception($"Path must be a Enumerable<T> but its a {expr.Type}");
|
||||||
@ -241,20 +241,43 @@ namespace PoweredSoft.DynamicLinq.Helpers
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static Expression InternalResolvePathExpression(ParameterExpression param, List<string> parts, SelectCollectionHandling selectCollectionHandling)
|
||||||
|
{
|
||||||
|
var isLast = parts.Count == 1;
|
||||||
|
var currentPart = parts.First();
|
||||||
|
var memberExpression = Expression.PropertyOrField(param, currentPart);
|
||||||
|
|
||||||
|
|
||||||
|
if (isLast)
|
||||||
|
return memberExpression;
|
||||||
|
|
||||||
|
if (!IsEnumerable(memberExpression))
|
||||||
|
return InternalResolvePathExpression(param, parts.Skip(1).ToList(), selectCollectionHandling);
|
||||||
|
|
||||||
|
// enumerable.
|
||||||
|
var listGenericArgumentType = memberExpression.Type.GetGenericArguments().First();
|
||||||
|
|
||||||
|
// sub param.
|
||||||
|
var innerParam = Expression.Parameter(listGenericArgumentType);
|
||||||
|
var innerExpression = InternalResolvePathExpression(innerParam, parts.Skip(1).ToList(), selectCollectionHandling);
|
||||||
|
var lambda = Expression.Lambda(innerExpression, innerParam);
|
||||||
|
|
||||||
|
if (selectCollectionHandling == SelectCollectionHandling.Select)
|
||||||
|
return Expression.Call(typeof(Enumerable), "Select", new Type[] { listGenericArgumentType, innerExpression.Type }, memberExpression, lambda);
|
||||||
|
|
||||||
|
return Expression.Call(typeof(Enumerable), "SelectMany", new Type[] { listGenericArgumentType, innerExpression.Type.GenericTypeArguments.First() }, memberExpression, lambda);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the right expression for a path supplied.
|
/// Returns the right expression for a path supplied.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="param">Expression.Parameter(typeOfClassOrInterface)</param>
|
/// <param name="param">Expression.Parameter(typeOfClassOrInterface)</param>
|
||||||
/// <param name="path">the path you wish to resolve example Contact.Profile.FirstName</param>
|
/// <param name="path">the path you wish to resolve example Contact.Profile.FirstName</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static Expression ResolvePathForExpression(ParameterExpression param, string path)
|
public static Expression ResolvePathForExpression(ParameterExpression param, string path, SelectCollectionHandling selectCollectionHandling = SelectCollectionHandling.Select)
|
||||||
{
|
{
|
||||||
Expression body = param;
|
var parts = path.Split('.').ToList();
|
||||||
foreach (var member in path.Split('.'))
|
return InternalResolvePathExpression(param, parts, selectCollectionHandling);
|
||||||
{
|
|
||||||
body = Expression.PropertyOrField(body, member);
|
|
||||||
}
|
|
||||||
return body;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ConstantExpression GetConstantSameAsLeftOperator(Expression member, object value)
|
public static ConstantExpression GetConstantSameAsLeftOperator(Expression member, object value)
|
||||||
|
Loading…
Reference in New Issue
Block a user