From 3a30c285feff89a5ec90fc1bf198bdeaa9d30f46 Mon Sep 17 00:00:00 2001 From: "agrath@gmail.com" Date: Thu, 17 Feb 2011 19:07:22 -1300 Subject: [PATCH] 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 --- .../DynamicNodeListOrdering.cs | 55 +++++++++++++ umbraco.MacroEngines.Juno/DynamicQueryable.cs | 80 +++++++++++++------ .../umbraco.MacroEngines.csproj | 1 + 3 files changed, 110 insertions(+), 26 deletions(-) create mode 100644 umbraco.MacroEngines.Juno/DynamicNodeListOrdering.cs diff --git a/umbraco.MacroEngines.Juno/DynamicNodeListOrdering.cs b/umbraco.MacroEngines.Juno/DynamicNodeListOrdering.cs new file mode 100644 index 0000000000..ff5ca8cc62 --- /dev/null +++ b/umbraco.MacroEngines.Juno/DynamicNodeListOrdering.cs @@ -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 func, DynamicNode node) + { + var value = func(node); + while (value is Func) + { + value = (value as Func)(node); + } + return value; + } + public static IOrderedQueryable OrderBy(object source, object key) + { + IEnumerable typedSource = source as IEnumerable; + LambdaExpression lambda = key as LambdaExpression; + Func func = (Func)lambda.Compile(); + IOrderedQueryable result = (IOrderedQueryable)typedSource.OrderBy(x => Reduce(func, x)).AsQueryable(); + return result; + } + public static IOrderedQueryable ThenBy(object source, object key) + { + IOrderedQueryable typedSource = source as IOrderedQueryable; + LambdaExpression lambda = key as LambdaExpression; + Func func = (Func)lambda.Compile(); + IOrderedQueryable result = (IOrderedQueryable)typedSource.ThenBy(x => Reduce(func, x)).AsQueryable(); + return result; + } + public static IOrderedQueryable OrderByDescending(object source, object key) + { + IEnumerable typedSource = source as IEnumerable; + LambdaExpression lambda = key as LambdaExpression; + Func func = (Func)lambda.Compile(); + IOrderedQueryable result = (IOrderedQueryable)typedSource.OrderByDescending(x => Reduce(func, x)).AsQueryable(); + return result; + } + public static IOrderedQueryable ThenByDescending(object source, object key) + { + IOrderedQueryable typedSource = source as IOrderedQueryable; + LambdaExpression lambda = key as LambdaExpression; + Func func = (Func)lambda.Compile(); + IOrderedQueryable result = (IOrderedQueryable)typedSource.ThenByDescending(x => Reduce(func, x)).AsQueryable(); + return result; + } + + } +} + diff --git a/umbraco.MacroEngines.Juno/DynamicQueryable.cs b/umbraco.MacroEngines.Juno/DynamicQueryable.cs index 98afe8a955..1a641427cb 100644 --- a/umbraco.MacroEngines.Juno/DynamicQueryable.cs +++ b/umbraco.MacroEngines.Juno/DynamicQueryable.cs @@ -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 typedSource = source as IQueryable; + if (!ordering.Contains(",")) { - //source list is DynamicNode and the lambda returns a Func - IQueryable typedSource = source as IQueryable; - Func func = (Func)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) + //source list is DynamicNode and the lambda returns a Func + Func func = (Func)lambda.Compile(); + return typedSource.OrderBy(delegate(DynamicNode node) { - value = (firstFuncResult as Func)(node); - } - return value; - }).AsQueryable(); + object value = -1; + var firstFuncResult = func(node); + if (firstFuncResult is Func) + { + value = (firstFuncResult as Func)(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 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 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) diff --git a/umbraco.MacroEngines.Juno/umbraco.MacroEngines.csproj b/umbraco.MacroEngines.Juno/umbraco.MacroEngines.csproj index ff99110c6a..ad25d2d101 100644 --- a/umbraco.MacroEngines.Juno/umbraco.MacroEngines.csproj +++ b/umbraco.MacroEngines.Juno/umbraco.MacroEngines.csproj @@ -63,6 +63,7 @@ +