Files
Umbraco-CMS/src/Umbraco.Web/Dynamics/DynamicPublishedContentListOrdering.cs
Shannon Deminick 842d7120e6 Obsoletes DynamicQueryable in MacroEngines lib, proxies all calls to new DynamicQueryable in Umbraco.Web.
Adds more support for NodeTypeAlias and DocumentTypeAlias param names for compatibility.
Adds IsDocumentType is-helper method.
Adds unit tests for complex Linq using a Typed IPublishedContent object.
Adds unit tests for complex Linq using dynamics.
Adds support for Single, SingleOrDefault, First, FirstOrDefault, Last, LastOrDefault to dynamics for both DynamicNode and DynamicPublishedContent + unit tests.
Adds support for 'Children' on DynamicNode to keep things consistent, no longer required to have to do 'ChildrenAsList'.
DynamicNode now implements INode... not sure why this wasn't like that before.
2012-10-06 23:41:42 +05:00

252 lines
12 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Umbraco.Web.Models;
namespace Umbraco.Web.Dynamics
{
public static class DynamicPublishedContentListOrdering
{
private static TOut Reduce<TOut>(Func<DynamicPublishedContent, TOut> func, DynamicPublishedContent publishedContent)
{
var value = func(publishedContent);
while (value is Func<DynamicPublishedContent, TOut>)
{
value = (value as Func<DynamicPublishedContent, TOut>)(publishedContent);
}
//when you're sorting a list of properties
//and one of those properties doesn't exist, it will come back as DynamicNull
//when that gets handled by the expression tree parser, it's converted to be false
//which lets .Where work properly with e.g. umbracoNaviHide which may not be defined
//on all properties
//this checks to see if the type of value is bool, and if it is, and it's false
//then return false
//in a case where Reduce<bool> is being called, this will return false, which is the
//same as the actual real value
//but when Reduce<object> [a dynamicnode dynamic property call] is called
//it will result in null, (because default(object) is null)
//which will cause the item with the missing property to sort up to the top of the list
if (value.GetType() == typeof(bool) && !((value as bool?) ?? false))
{
return default(TOut);
}
if (value.GetType() == typeof(string) && string.IsNullOrEmpty((value as string)))
{
return default(TOut);
}
return (TOut)value;
}
public static IOrderedQueryable<DynamicPublishedContent> OrderBy(object source, object key)
{
IEnumerable<DynamicPublishedContent> typedSource = source as IEnumerable<DynamicPublishedContent>;
LambdaExpression lambda = key as LambdaExpression;
//if the lambda we have returns an actual property, not a dynamic one,
//then the TOut of the func will be the actual type, not object
//Func<DynamicNode, object> func = (Func<DynamicNode, object>)lambda.Compile();
var func = lambda.Compile();
var TOut = func.GetType().GetGenericArguments()[1];
IOrderedQueryable<DynamicPublishedContent> result = null;
if (TOut == typeof(Func<DynamicPublishedContent, object>))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.OrderBy(x => Reduce<object>(func as Func<DynamicPublishedContent, object>, x))
.AsQueryable();
}
if (TOut == typeof(object))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.OrderBy(x => Reduce<object>(func as Func<DynamicPublishedContent, object>, x))
.AsQueryable();
}
if (TOut == typeof(bool))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.OrderBy(x => Reduce<bool>(func as Func<DynamicPublishedContent, bool>, x))
.AsQueryable();
}
if (TOut == typeof(decimal))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.OrderBy(x => Reduce<decimal>(func as Func<DynamicPublishedContent, decimal>, x))
.AsQueryable();
}
if (TOut == typeof(int))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.OrderBy(x => Reduce<int>(func as Func<DynamicPublishedContent, int>, x))
.AsQueryable();
}
if (TOut == typeof(string))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.OrderBy(x => Reduce<string>(func as Func<DynamicPublishedContent, string>, x))
.AsQueryable();
}
if (TOut == typeof(DateTime))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.OrderBy(x => Reduce<DateTime>(func as Func<DynamicPublishedContent, DateTime>, x))
.AsQueryable();
}
return result;
}
public static IOrderedQueryable<DynamicPublishedContent> ThenBy(object source, object key)
{
IOrderedQueryable<DynamicPublishedContent> typedSource = source as IOrderedQueryable<DynamicPublishedContent>;
LambdaExpression lambda = key as LambdaExpression;
var func = lambda.Compile();
var TOut = func.GetType().GetGenericArguments()[1];
IOrderedQueryable<DynamicPublishedContent> result = null;
if (TOut == typeof(Func<DynamicPublishedContent, object>))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.ThenBy(x => Reduce<object>(func as Func<DynamicPublishedContent, object>, x))
.AsQueryable();
}
if (TOut == typeof(object))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.ThenBy(x => Reduce<object>(func as Func<DynamicPublishedContent, object>, x))
.AsQueryable();
}
if (TOut == typeof(bool))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.ThenBy(x => Reduce<bool>(func as Func<DynamicPublishedContent, bool>, x))
.AsQueryable();
}
if (TOut == typeof(decimal))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.ThenBy(x => Reduce<decimal>(func as Func<DynamicPublishedContent, decimal>, x))
.AsQueryable();
}
if (TOut == typeof(int))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.ThenBy(x => Reduce<int>(func as Func<DynamicPublishedContent, int>, x))
.AsQueryable();
}
if (TOut == typeof(string))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.ThenBy(x => Reduce<string>(func as Func<DynamicPublishedContent, string>, x))
.AsQueryable();
}
if (TOut == typeof(DateTime))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.ThenBy(x => Reduce<DateTime>(func as Func<DynamicPublishedContent, DateTime>, x))
.AsQueryable();
}
return result;
}
public static IOrderedQueryable<DynamicPublishedContent> OrderByDescending(object source, object key)
{
IEnumerable<DynamicPublishedContent> typedSource = source as IEnumerable<DynamicPublishedContent>;
LambdaExpression lambda = key as LambdaExpression;
var func = lambda.Compile();
var TOut = func.GetType().GetGenericArguments()[1];
IOrderedQueryable<DynamicPublishedContent> result = null;
if (TOut == typeof(Func<DynamicPublishedContent, object>))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.OrderByDescending(x => Reduce<object>(func as Func<DynamicPublishedContent, object>, x))
.AsQueryable();
}
if (TOut == typeof(object))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.OrderByDescending(x => Reduce<object>(func as Func<DynamicPublishedContent, object>, x))
.AsQueryable();
}
if (TOut == typeof(bool))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.OrderByDescending(x => Reduce<bool>(func as Func<DynamicPublishedContent, bool>, x))
.AsQueryable();
}
if (TOut == typeof(decimal))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.OrderByDescending(x => Reduce<decimal>(func as Func<DynamicPublishedContent, decimal>, x))
.AsQueryable();
}
if (TOut == typeof(int))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.OrderByDescending(x => Reduce<int>(func as Func<DynamicPublishedContent, int>, x))
.AsQueryable();
}
if (TOut == typeof(string))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.OrderByDescending(x => Reduce<string>(func as Func<DynamicPublishedContent, string>, x))
.AsQueryable();
}
if (TOut == typeof(DateTime))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.OrderByDescending(x => Reduce<DateTime>(func as Func<DynamicPublishedContent, DateTime>, x))
.AsQueryable();
}
return result;
}
public static IOrderedQueryable<DynamicPublishedContent> ThenByDescending(object source, object key)
{
IOrderedQueryable<DynamicPublishedContent> typedSource = source as IOrderedQueryable<DynamicPublishedContent>;
LambdaExpression lambda = key as LambdaExpression;
var func = lambda.Compile();
var TOut = func.GetType().GetGenericArguments()[1];
IOrderedQueryable<DynamicPublishedContent> result = null;
if (TOut == typeof(Func<DynamicPublishedContent, object>))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.ThenByDescending(x => Reduce<object>(func as Func<DynamicPublishedContent, object>, x))
.AsQueryable();
}
if (TOut == typeof(object))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.ThenByDescending(x => Reduce<object>(func as Func<DynamicPublishedContent, object>, x))
.AsQueryable();
}
if (TOut == typeof(bool))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.ThenByDescending(x => Reduce<bool>(func as Func<DynamicPublishedContent, bool>, x))
.AsQueryable();
}
if (TOut == typeof(decimal))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.ThenByDescending(x => Reduce<decimal>(func as Func<DynamicPublishedContent, decimal>, x))
.AsQueryable();
}
if (TOut == typeof(int))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.ThenByDescending(x => Reduce<int>(func as Func<DynamicPublishedContent, int>, x))
.AsQueryable();
}
if (TOut == typeof(string))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.ThenByDescending(x => Reduce<string>(func as Func<DynamicPublishedContent, string>, x))
.AsQueryable();
}
if (TOut == typeof(DateTime))
{
result = (IOrderedQueryable<DynamicPublishedContent>)typedSource
.ThenByDescending(x => Reduce<DateTime>(func as Func<DynamicPublishedContent, DateTime>, x))
.AsQueryable();
}
return result;
}
}
}