Implemented Pluck/Select to extract a given property from a DynamicNodeList and return it as a List<T>

Example:
var colours = @Model.Children.Select("colour");
//Red, Green, Blue ...
Uses the parser from .Where internally
Aliased as .Pluck
This commit is contained in:
agrath@gmail.com
2011-03-12 16:29:02 -13:00
parent 1a2bba4b2b
commit 1b060dfdbf
2 changed files with 86 additions and 9 deletions

View File

@@ -48,6 +48,54 @@ namespace umbraco.MacroEngines
result = new DynamicNodeList(this.OrderBy<DynamicNode>(args.First().ToString()).ToList());
return true;
}
if (name == "Pluck" || name == "Select")
{
string predicate = args.First().ToString();
var values = args.Skip(1).ToArray();
var query = (IQueryable<object>)this.Select(predicate, values);
object firstItem = query.FirstOrDefault();
if (firstItem == null)
{
result = new DynamicNull();
}
else
{
var types = from i in query
group i by i.GetType() into g
orderby g.Count() descending
select new { g, Instances = g.Count() };
var dominantType = types.First().g.Key;
//remove items that are not the dominant type
//e.g. string,string,string,string,false[DynamicNull],string
var itemsOfDominantTypeOnly = query.ToList();
itemsOfDominantTypeOnly.RemoveAll(item => !item.GetType().IsAssignableFrom(dominantType));
if (dominantType == typeof(string))
{
result = (List<string>)itemsOfDominantTypeOnly.Cast<string>().ToList();
}
else if (dominantType == typeof(int))
{
result = (List<int>)itemsOfDominantTypeOnly.Cast<int>().ToList();
}
else if (dominantType == typeof(decimal))
{
result = (List<decimal>)itemsOfDominantTypeOnly.Cast<decimal>().ToList();
}
else if (dominantType == typeof(bool))
{
result = (List<bool>)itemsOfDominantTypeOnly.Cast<bool>().ToList();
}
else if (dominantType == typeof(DateTime))
{
result = (List<DateTime>)itemsOfDominantTypeOnly.Cast<DateTime>().ToList();
}
else
{
result = query.ToList();
}
}
return true;
}
try
{
//Property?
@@ -161,14 +209,18 @@ namespace umbraco.MacroEngines
return Items.GetEnumerator();
}
public IQueryable<T> Where<T>(string predicate, params object[] values)
private IQueryable<T> Where<T>(string predicate, params object[] values)
{
return ((IQueryable<T>)Items.AsQueryable()).Where(predicate, values);
}
public IQueryable<T> OrderBy<T>(string key)
private IQueryable<T> OrderBy<T>(string key)
{
return ((IQueryable<T>)Items.AsQueryable()).OrderBy(key);
}
private IQueryable Select(string predicate, params object[] values)
{
return DynamicQueryable.Select(Items.AsQueryable(), predicate, values);
}
public void Add(DynamicNode node)
{

View File

@@ -89,16 +89,41 @@ namespace System.Linq.Dynamic
}
}
public static IQueryable Select(this IQueryable source, string selector, params object[] values)
public static IQueryable Select(this IQueryable<DynamicNode> source, string selector, params object[] values)
{
if (source == null) throw new ArgumentNullException("source");
if (selector == null) throw new ArgumentNullException("selector");
LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, null, selector, values);
return source.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "Select",
new Type[] { source.ElementType, lambda.Body.Type },
source.Expression, Expression.Quote(lambda)));
LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(object), selector, values);
if (lambda.Parameters.Count > 0 && lambda.Parameters[0].Type == typeof(DynamicNode))
{
//source list is DynamicNode and the lambda returns a Func<object>
IQueryable<DynamicNode> typedSource = source as IQueryable<DynamicNode>;
var compiledFunc = lambda.Compile();
Func<DynamicNode, object> func = null;
if (compiledFunc is Func<DynamicNode, object>)
{
func = (Func<DynamicNode, object>)compiledFunc;
}
return typedSource.Select(delegate(DynamicNode node)
{
object value = null;
value = func(node);
if (value is Func<DynamicNode, object>)
{
var innerValue = (value as Func<DynamicNode, object>)(node);
return innerValue;
}
return value;
}).AsQueryable();
}
else
{
return source.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "Select",
new Type[] { source.ElementType, lambda.Body.Type },
source.Expression, Expression.Quote(lambda)));
}
}
public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, params object[] values)