ready for pull-request.
This commit is contained in:
parent
7d9755ef58
commit
a0c59a613a
@ -7,10 +7,29 @@ using PoweredSoft.DynamicLinq.Helpers;
|
|||||||
|
|
||||||
namespace PoweredSoft.DynamicLinq.Test
|
namespace PoweredSoft.DynamicLinq.Test
|
||||||
{
|
{
|
||||||
|
class Foo
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ListOfFoo : List<Foo>
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class HelpersTests
|
public class HelpersTests
|
||||||
{
|
{
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestInheritanceOfListAsGenericEnumerableType()
|
||||||
|
{
|
||||||
|
var shouldBeTrue = QueryableHelpers.IsGenericEnumerable(typeof(ListOfFoo));
|
||||||
|
Assert.IsTrue(shouldBeTrue);
|
||||||
|
var type = QueryableHelpers.GetTypeOfEnumerable(typeof(ListOfFoo), true);
|
||||||
|
Assert.IsTrue(type == typeof(Foo));
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestCreateFilterExpression()
|
public void TestCreateFilterExpression()
|
||||||
{
|
{
|
||||||
|
@ -23,9 +23,69 @@ namespace PoweredSoft.DynamicLinq.Test
|
|||||||
public List<string> FirstNames { get; set; }
|
public List<string> FirstNames { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class MockPerson
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public MockListOfPhone Phones { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MockPhone
|
||||||
|
{
|
||||||
|
public string Number { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MockListOfPhone : List<MockPhone>
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class SelectTests
|
public class SelectTests
|
||||||
{
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void TestSelectWithInheritedList()
|
||||||
|
{
|
||||||
|
var list = new List<MockPerson>()
|
||||||
|
{
|
||||||
|
new MockPerson
|
||||||
|
{
|
||||||
|
Name = "David Lebee",
|
||||||
|
Phones = new MockListOfPhone
|
||||||
|
{
|
||||||
|
new MockPhone
|
||||||
|
{
|
||||||
|
Number = "0000000000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new MockPerson
|
||||||
|
{
|
||||||
|
Name = "Yubing Liang",
|
||||||
|
Phones = new MockListOfPhone
|
||||||
|
{
|
||||||
|
new MockPhone
|
||||||
|
{
|
||||||
|
Number = "1111111111"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var names = list.AsQueryable()
|
||||||
|
.Where(t => t.Equal("Phones.Number", "1111111111"))
|
||||||
|
.Select(t =>
|
||||||
|
{
|
||||||
|
t.Path("Name");
|
||||||
|
t.FirstOrDefault("Phones.Number", "Number", SelectCollectionHandling.Flatten);
|
||||||
|
})
|
||||||
|
.ToDynamicClassList();
|
||||||
|
|
||||||
|
Assert.IsTrue(names.Count() == 1);
|
||||||
|
var firstPerson = names.First();
|
||||||
|
Assert.AreEqual("Yubing Liang", firstPerson.GetDynamicPropertyValue<string>("Name"));
|
||||||
|
Assert.AreEqual("1111111111", firstPerson.GetDynamicPropertyValue<string>("Number"));
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestSelect()
|
public void TestSelect()
|
||||||
{
|
{
|
||||||
|
@ -135,9 +135,9 @@ namespace PoweredSoft.DynamicLinq.Test
|
|||||||
// subject.
|
// subject.
|
||||||
var posts = new List<Post>()
|
var posts = new List<Post>()
|
||||||
{
|
{
|
||||||
new Post { Id = 1, AuthorId = 1, Title = "Hello 1", Content = "World" },
|
new Post { Id = 1, AuthorId = 1, Title = "Hello 1", Content = "World"},
|
||||||
new Post { Id = 2, AuthorId = 1, Title = "Hello 2", Content = "World" },
|
new Post { Id = 2, AuthorId = 1, Title = "Hello 2", Content = "World"},
|
||||||
new Post { Id = 3, AuthorId = 2, Title = "Hello 3", Content = "World" },
|
new Post { Id = 3, AuthorId = 2, Title = "Hello 3", Content = "World"},
|
||||||
};
|
};
|
||||||
|
|
||||||
// the query.
|
// the query.
|
||||||
@ -151,5 +151,24 @@ namespace PoweredSoft.DynamicLinq.Test
|
|||||||
Assert.IsTrue(first.Id == 3);
|
Assert.IsTrue(first.Id == 3);
|
||||||
Assert.IsTrue(second.Id == 1);
|
Assert.IsTrue(second.Id == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestingSort2()
|
||||||
|
{
|
||||||
|
// subject.
|
||||||
|
var posts = new List<Post>()
|
||||||
|
{
|
||||||
|
new Post { Id = 1, AuthorId = 1, Title = "Hello 1", Content = "World", Comments = new List<Comment> { } },
|
||||||
|
new Post { Id = 2, AuthorId = 1, Title = "Hello 2", Content = "World", Comments = new List<Comment> { } },
|
||||||
|
new Post { Id = 3, AuthorId = 2, Title = "Hello 3", Content = "World", Comments = new List<Comment> { } },
|
||||||
|
};
|
||||||
|
|
||||||
|
// the query.
|
||||||
|
var query = posts.AsQueryable();
|
||||||
|
|
||||||
|
// just testing that the expressionm can be created, some drivers support seleting in collections.
|
||||||
|
var query2 = query.OrderByDescending("Comments");
|
||||||
|
var query3 = query.OrderByDescending("Comments.PostId");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,7 +253,7 @@ namespace PoweredSoft.DynamicLinq.Helpers
|
|||||||
|
|
||||||
Expression selectExpression;
|
Expression selectExpression;
|
||||||
if (QueryableHelpers.IsGenericEnumerable(innerSelectType) && selectCollectionHandling == SelectCollectionHandling.Flatten)
|
if (QueryableHelpers.IsGenericEnumerable(innerSelectType) && selectCollectionHandling == SelectCollectionHandling.Flatten)
|
||||||
selectExpression = Expression.Call(typeof(Enumerable), "SelectMany", new Type[] { selectType, innerSelectType.GenericTypeArguments.First() }, parameter, innerLambdaExpression);
|
selectExpression = Expression.Call(typeof(Enumerable), "SelectMany", new Type[] { selectType, QueryableHelpers.GetTypeOfEnumerable(innerSelectType, true) }, parameter, innerLambdaExpression);
|
||||||
else
|
else
|
||||||
selectExpression = Expression.Call(typeof(Enumerable), "Select", new Type[] { selectType, innerSelectType }, parameter, innerLambdaExpression);
|
selectExpression = Expression.Call(typeof(Enumerable), "Select", new Type[] { selectType, innerSelectType }, parameter, innerLambdaExpression);
|
||||||
|
|
||||||
@ -359,7 +359,7 @@ namespace PoweredSoft.DynamicLinq.Helpers
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// enumerable.
|
// enumerable.
|
||||||
var listGenericArgumentType = memberExpression.Type.GetGenericArguments().First();
|
var listGenericArgumentType = QueryableHelpers.GetTypeOfEnumerable(memberExpression.Type, true);
|
||||||
|
|
||||||
// sub param.
|
// sub param.
|
||||||
var innerParam = Expression.Parameter(listGenericArgumentType);
|
var innerParam = Expression.Parameter(listGenericArgumentType);
|
||||||
@ -432,7 +432,7 @@ namespace PoweredSoft.DynamicLinq.Helpers
|
|||||||
public static IQueryable CreateOrderByExpression(IQueryable query, string path, QueryOrderByDirection direction, bool append = true)
|
public static IQueryable CreateOrderByExpression(IQueryable query, string path, QueryOrderByDirection direction, bool append = true)
|
||||||
{
|
{
|
||||||
var parameter = Expression.Parameter(query.ElementType, "t");
|
var parameter = Expression.Parameter(query.ElementType, "t");
|
||||||
var member = QueryableHelpers.ResolvePathForExpression(parameter, path);
|
var member = QueryableHelpers.ResolvePathForExpression(parameter, path, false);
|
||||||
|
|
||||||
string sortCommand = null;
|
string sortCommand = null;
|
||||||
if (direction == QueryOrderByDirection.Descending)
|
if (direction == QueryOrderByDirection.Descending)
|
||||||
@ -503,7 +503,7 @@ namespace PoweredSoft.DynamicLinq.Helpers
|
|||||||
|
|
||||||
if (IsGenericEnumerable(memberExpression))
|
if (IsGenericEnumerable(memberExpression))
|
||||||
{
|
{
|
||||||
var listGenericArgumentType = memberExpression.Type.GetGenericArguments().First();
|
var listGenericArgumentType = QueryableHelpers.GetTypeOfEnumerable(memberExpression.Type, true);
|
||||||
var innerParameter = Expression.Parameter(listGenericArgumentType, $"t{++recursionStep}");
|
var innerParameter = Expression.Parameter(listGenericArgumentType, $"t{++recursionStep}");
|
||||||
var innerLambda = InternalCreateConditionExpression(recursionStep, listGenericArgumentType, innerParameter, innerParameter, parts.Skip(1).ToList(), condition, value, convertStrategy, collectionHandling, nullChecking, stringComparison, negate);
|
var innerLambda = InternalCreateConditionExpression(recursionStep, listGenericArgumentType, innerParameter, innerParameter, parts.Skip(1).ToList(), condition, value, convertStrategy, collectionHandling, nullChecking, stringComparison, negate);
|
||||||
|
|
||||||
@ -623,12 +623,43 @@ namespace PoweredSoft.DynamicLinq.Helpers
|
|||||||
public static bool IsGenericEnumerable(Expression member) => IsGenericEnumerable(member.Type);
|
public static bool IsGenericEnumerable(Expression member) => IsGenericEnumerable(member.Type);
|
||||||
public static bool IsGenericEnumerable(Type type)
|
public static bool IsGenericEnumerable(Type type)
|
||||||
{
|
{
|
||||||
if (!type.IsGenericType)
|
if (type == typeof(string))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var genericArgumentType = type.GenericTypeArguments.First();
|
if (type.IsGenericType)
|
||||||
var ret = typeof(IEnumerable<>).MakeGenericType(genericArgumentType).IsAssignableFrom(type);
|
{
|
||||||
return ret;
|
var makeGenericType = typeof(IEnumerable<>).MakeGenericType(type.GetGenericArguments()[0]);
|
||||||
|
var possible = makeGenericType.IsAssignableFrom(type);
|
||||||
|
if (possible)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = type.GetInterfaces().Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Type GetTypeOfEnumerable(Type genericEnumerableType, bool throwIfNotEnumerable)
|
||||||
|
{
|
||||||
|
Type result = null;
|
||||||
|
|
||||||
|
if (genericEnumerableType.IsGenericType)
|
||||||
|
{
|
||||||
|
var makeGenericType = typeof(IEnumerable<>).MakeGenericType(genericEnumerableType.GetGenericArguments()[0]);
|
||||||
|
var possible = makeGenericType.IsAssignableFrom(genericEnumerableType);
|
||||||
|
if (possible)
|
||||||
|
return genericEnumerableType.GetGenericArguments()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
result = genericEnumerableType.GetInterfaces().FirstOrDefault(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>));
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
if (throwIfNotEnumerable)
|
||||||
|
throw new Exception("Not a IEnumerable<T>");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.GetGenericArguments().First();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ namespace PoweredSoft.DynamicLinq.Parser
|
|||||||
{
|
{
|
||||||
Type = memberExpression.Type,
|
Type = memberExpression.Type,
|
||||||
IsGenericEnumerable = QueryableHelpers.IsGenericEnumerable(memberExpression),
|
IsGenericEnumerable = QueryableHelpers.IsGenericEnumerable(memberExpression),
|
||||||
EnumerableType = memberExpression.Type.GenericTypeArguments.FirstOrDefault(),
|
EnumerableType = QueryableHelpers.GetTypeOfEnumerable(memberExpression.Type, false),
|
||||||
Parent = parent,
|
Parent = parent,
|
||||||
Name = pp
|
Name = pp
|
||||||
};
|
};
|
||||||
|
@ -74,8 +74,9 @@ namespace PoweredSoft.DynamicLinq.Resolver
|
|||||||
if (isSelectMany)
|
if (isSelectMany)
|
||||||
{
|
{
|
||||||
var selectType = parent.GroupEnumerableType();
|
var selectType = parent.GroupEnumerableType();
|
||||||
|
var groupExpressionEnumerableType = QueryableHelpers.GetTypeOfEnumerable(groupExpression.Type, true);
|
||||||
var selectExpression = Expression.Call(typeof(Enumerable), "SelectMany",
|
var selectExpression = Expression.Call(typeof(Enumerable), "SelectMany",
|
||||||
new Type[] { selectType, groupExpression.Type.GenericTypeArguments.First() },
|
new Type[] { selectType, groupExpressionEnumerableType },
|
||||||
parentExpression, groupExpressionLambda);
|
parentExpression, groupExpressionLambda);
|
||||||
currentExpression = selectExpression;
|
currentExpression = selectExpression;
|
||||||
}
|
}
|
||||||
@ -109,9 +110,10 @@ namespace PoweredSoft.DynamicLinq.Resolver
|
|||||||
|
|
||||||
if (isSelectMany)
|
if (isSelectMany)
|
||||||
{
|
{
|
||||||
|
var currentExpressionEnumerableType = QueryableHelpers.GetTypeOfEnumerable(currentExpression.Type, true);
|
||||||
var currentExpressionLambda = Expression.Lambda(currentExpression, group.Parameter);
|
var currentExpressionLambda = Expression.Lambda(currentExpression, group.Parameter);
|
||||||
currentExpression = Expression.Call(typeof(Enumerable), "SelectMany",
|
currentExpression = Expression.Call(typeof(Enumerable), "SelectMany",
|
||||||
new Type[] { selectType, currentExpression.Type.GenericTypeArguments.First() },
|
new Type[] { selectType, currentExpressionEnumerableType },
|
||||||
parentExpression, currentExpressionLambda);
|
parentExpression, currentExpressionLambda);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -144,7 +146,8 @@ namespace PoweredSoft.DynamicLinq.Resolver
|
|||||||
Expression ifTrueExpression = null;
|
Expression ifTrueExpression = null;
|
||||||
if (QueryableHelpers.IsGenericEnumerable(nullType))
|
if (QueryableHelpers.IsGenericEnumerable(nullType))
|
||||||
{
|
{
|
||||||
var listType = typeof(List<>).MakeGenericType(nullType.GenericTypeArguments.First());
|
var enumerableType = QueryableHelpers.GetTypeOfEnumerable(nullType, true);
|
||||||
|
var listType = typeof(List<>).MakeGenericType(enumerableType);
|
||||||
ifTrueExpression = Expression.New(listType);
|
ifTrueExpression = Expression.New(listType);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user