Updated .OrderBy implementation to support OrderBy,OrderByDescending,ThenBy,ThenByDescending properly on DynamicNodeList
Usage is: @foreach(var item in home.ChildItems.OrderBy("catCount, colour desc"))
If you use the simple form of home.ChildItems.OrderBy("catCount") it will use a simpler/faster implementation
This commit is contained in:
55
umbraco.MacroEngines.Juno/DynamicNodeListOrdering.cs
Normal file
55
umbraco.MacroEngines.Juno/DynamicNodeListOrdering.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace umbraco.MacroEngines
|
||||
{
|
||||
public static class DynamicNodeListOrdering
|
||||
{
|
||||
private static object Reduce(Func<DynamicNode, object> func, DynamicNode node)
|
||||
{
|
||||
var value = func(node);
|
||||
while (value is Func<DynamicNode, object>)
|
||||
{
|
||||
value = (value as Func<DynamicNode, object>)(node);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
public static IOrderedQueryable<DynamicNode> OrderBy(object source, object key)
|
||||
{
|
||||
IEnumerable<DynamicNode> typedSource = source as IEnumerable<DynamicNode>;
|
||||
LambdaExpression lambda = key as LambdaExpression;
|
||||
Func<DynamicNode, object> func = (Func<DynamicNode, object>)lambda.Compile();
|
||||
IOrderedQueryable<DynamicNode> result = (IOrderedQueryable<DynamicNode>)typedSource.OrderBy(x => Reduce(func, x)).AsQueryable();
|
||||
return result;
|
||||
}
|
||||
public static IOrderedQueryable<DynamicNode> ThenBy(object source, object key)
|
||||
{
|
||||
IOrderedQueryable<DynamicNode> typedSource = source as IOrderedQueryable<DynamicNode>;
|
||||
LambdaExpression lambda = key as LambdaExpression;
|
||||
Func<DynamicNode, object> func = (Func<DynamicNode, object>)lambda.Compile();
|
||||
IOrderedQueryable<DynamicNode> result = (IOrderedQueryable<DynamicNode>)typedSource.ThenBy(x => Reduce(func, x)).AsQueryable();
|
||||
return result;
|
||||
}
|
||||
public static IOrderedQueryable<DynamicNode> OrderByDescending(object source, object key)
|
||||
{
|
||||
IEnumerable<DynamicNode> typedSource = source as IEnumerable<DynamicNode>;
|
||||
LambdaExpression lambda = key as LambdaExpression;
|
||||
Func<DynamicNode, object> func = (Func<DynamicNode, object>)lambda.Compile();
|
||||
IOrderedQueryable<DynamicNode> result = (IOrderedQueryable<DynamicNode>)typedSource.OrderByDescending(x => Reduce(func, x)).AsQueryable();
|
||||
return result;
|
||||
}
|
||||
public static IOrderedQueryable<DynamicNode> ThenByDescending(object source, object key)
|
||||
{
|
||||
IOrderedQueryable<DynamicNode> typedSource = source as IOrderedQueryable<DynamicNode>;
|
||||
LambdaExpression lambda = key as LambdaExpression;
|
||||
Func<DynamicNode, object> func = (Func<DynamicNode, object>)lambda.Compile();
|
||||
IOrderedQueryable<DynamicNode> result = (IOrderedQueryable<DynamicNode>)typedSource.ThenByDescending(x => Reduce(func, x)).AsQueryable();
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,45 +84,73 @@ namespace System.Linq.Dynamic
|
||||
|
||||
public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values)
|
||||
{
|
||||
LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(bool), ordering, values);
|
||||
if (lambda.Parameters.Count > 0 && lambda.Parameters[0].Type == typeof(DynamicNode))
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
if (ordering == null) throw new ArgumentNullException("ordering");
|
||||
|
||||
IQueryable<DynamicNode> typedSource = source as IQueryable<DynamicNode>;
|
||||
if (!ordering.Contains(","))
|
||||
{
|
||||
//source list is DynamicNode and the lambda returns a Func<object>
|
||||
IQueryable<DynamicNode> typedSource = source as IQueryable<DynamicNode>;
|
||||
Func<DynamicNode, object> func = (Func<DynamicNode, object>)lambda.Compile();
|
||||
return typedSource.OrderBy(delegate(DynamicNode node)
|
||||
LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(bool), ordering, values);
|
||||
if (lambda.Parameters.Count > 0 && lambda.Parameters[0].Type == typeof(DynamicNode))
|
||||
{
|
||||
object value = -1;
|
||||
var firstFuncResult = func(node);
|
||||
if (firstFuncResult is Func<DynamicNode, object>)
|
||||
//source list is DynamicNode and the lambda returns a Func<object>
|
||||
Func<DynamicNode, object> func = (Func<DynamicNode, object>)lambda.Compile();
|
||||
return typedSource.OrderBy(delegate(DynamicNode node)
|
||||
{
|
||||
value = (firstFuncResult as Func<DynamicNode, object>)(node);
|
||||
}
|
||||
return value;
|
||||
}).AsQueryable();
|
||||
object value = -1;
|
||||
var firstFuncResult = func(node);
|
||||
if (firstFuncResult is Func<DynamicNode, object>)
|
||||
{
|
||||
value = (firstFuncResult as Func<DynamicNode, object>)(node);
|
||||
}
|
||||
return value;
|
||||
}).AsQueryable();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
bool isDynamicNodeList = false;
|
||||
if (typedSource != null)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
if (ordering == null) throw new ArgumentNullException("ordering");
|
||||
ParameterExpression[] parameters = new ParameterExpression[] {
|
||||
isDynamicNodeList = true;
|
||||
}
|
||||
|
||||
ParameterExpression[] parameters = new ParameterExpression[] {
|
||||
Expression.Parameter(source.ElementType, "") };
|
||||
ExpressionParser parser = new ExpressionParser(parameters, ordering, values);
|
||||
IEnumerable<DynamicOrdering> orderings = parser.ParseOrdering();
|
||||
Expression queryExpr = source.Expression;
|
||||
string methodAsc = "OrderBy";
|
||||
string methodDesc = "OrderByDescending";
|
||||
foreach (DynamicOrdering o in orderings)
|
||||
ExpressionParser parser = new ExpressionParser(parameters, ordering, values);
|
||||
IEnumerable<DynamicOrdering> orderings = parser.ParseOrdering();
|
||||
Expression queryExpr = source.Expression;
|
||||
string methodAsc = "OrderBy";
|
||||
string methodDesc = "OrderByDescending";
|
||||
foreach (DynamicOrdering o in orderings)
|
||||
{
|
||||
if (!isDynamicNodeList)
|
||||
{
|
||||
queryExpr = Expression.Call(
|
||||
typeof(Queryable), o.Ascending ? methodAsc : methodDesc,
|
||||
new Type[] { source.ElementType, o.Selector.Type },
|
||||
queryExpr, Expression.Quote(Expression.Lambda(o.Selector, parameters)));
|
||||
methodAsc = "ThenBy";
|
||||
methodDesc = "ThenByDescending";
|
||||
}
|
||||
return source.Provider.CreateQuery(queryExpr);
|
||||
else
|
||||
{
|
||||
//reroute each stacked Expression.Call into our own methods that know how to deal
|
||||
//with DynamicNode
|
||||
queryExpr = Expression.Call(
|
||||
typeof(DynamicNodeListOrdering),
|
||||
o.Ascending ? methodAsc : methodDesc,
|
||||
null,
|
||||
queryExpr,
|
||||
Expression.Quote(Expression.Lambda(o.Selector, parameters))
|
||||
);
|
||||
}
|
||||
methodAsc = "ThenBy";
|
||||
methodDesc = "ThenByDescending";
|
||||
}
|
||||
if (isDynamicNodeList)
|
||||
{
|
||||
return typedSource.Provider.CreateQuery(queryExpr);
|
||||
}
|
||||
return source.Provider.CreateQuery(queryExpr);
|
||||
|
||||
}
|
||||
|
||||
public static IQueryable Take(this IQueryable source, int count)
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="DLRScriptingEngine.cs" />
|
||||
<Compile Include="DynamicDictionary.cs" />
|
||||
<Compile Include="DynamicNodeListOrdering.cs" />
|
||||
<Compile Include="DynamicQueryableBinders.cs" />
|
||||
<Compile Include="DynamicMedia.cs" />
|
||||
<Compile Include="DynamicNode.cs" />
|
||||
|
||||
Reference in New Issue
Block a user