2012-08-17 04:27:47 +06:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Dynamic;
|
2012-10-04 01:31:08 +05:00
|
|
|
|
using Umbraco.Core.Dynamics;
|
2012-08-17 04:27:47 +06:00
|
|
|
|
using System.Collections;
|
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
|
2012-10-04 01:31:08 +05:00
|
|
|
|
namespace Umbraco.Core.Models
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
2012-10-04 01:31:08 +05:00
|
|
|
|
public class DynamicPublishedContentList : DynamicObject, IEnumerable<DynamicPublishedContentBase>
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
2012-10-04 01:31:08 +05:00
|
|
|
|
internal List<DynamicPublishedContentBase> Items { get; set; }
|
2012-08-17 04:27:47 +06:00
|
|
|
|
|
2012-10-02 22:51:53 +05:00
|
|
|
|
public DynamicPublishedContentList()
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
2012-10-04 01:31:08 +05:00
|
|
|
|
Items = new List<DynamicPublishedContentBase>();
|
2012-08-17 04:27:47 +06:00
|
|
|
|
}
|
2012-10-04 01:31:08 +05:00
|
|
|
|
public DynamicPublishedContentList(IEnumerable<DynamicPublishedContentBase> items)
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
2012-10-04 01:31:08 +05:00
|
|
|
|
var list = items.ToList();
|
2012-08-17 04:27:47 +06:00
|
|
|
|
Items = list;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-10-02 22:51:53 +05:00
|
|
|
|
public DynamicPublishedContentList(IEnumerable<IPublishedContent> items)
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
2012-10-04 01:31:08 +05:00
|
|
|
|
var list = items.Select(x => new DynamicPublishedContentBase(x)).ToList();
|
2012-08-17 04:27:47 +06:00
|
|
|
|
Items = list;
|
|
|
|
|
|
}
|
|
|
|
|
|
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
|
|
|
|
|
|
{
|
|
|
|
|
|
int index = (int)indexes[0];
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
result = this.Items.ElementAt(index);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (IndexOutOfRangeException)
|
|
|
|
|
|
{
|
|
|
|
|
|
result = new DynamicNull();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
|
|
|
|
|
|
{
|
2012-08-24 23:44:47 +07:00
|
|
|
|
|
|
|
|
|
|
//TODO: We MUST cache the result here, it is very expensive to keep finding extension methods and processing this stuff!
|
|
|
|
|
|
|
2012-08-28 09:20:30 +07:00
|
|
|
|
//TODO: Nowhere here are we checking if args is the correct length!
|
|
|
|
|
|
|
|
|
|
|
|
//NOTE: For many of these we could actually leave them out since we are executing custom extension methods and because
|
|
|
|
|
|
// we implement IEnumerable<T> they will execute just fine, however, to do that will be quite a bit slower than checking here.
|
|
|
|
|
|
|
2012-08-17 04:27:47 +06:00
|
|
|
|
var name = binder.Name;
|
|
|
|
|
|
if (name == "Where")
|
|
|
|
|
|
{
|
|
|
|
|
|
string predicate = args.First().ToString();
|
|
|
|
|
|
var values = args.Skip(1).ToArray();
|
2012-08-28 09:20:30 +07:00
|
|
|
|
//TODO: We are pre-resolving the where into a ToList() here which will have performance impacts if there where clauses
|
|
|
|
|
|
// are nested! We should somehow support an QueryableDocumentList!
|
2012-10-04 01:31:08 +05:00
|
|
|
|
result = new DynamicPublishedContentList(this.Where<DynamicPublishedContentBase>(predicate, values).ToList());
|
2012-08-17 04:27:47 +06:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (name == "OrderBy")
|
|
|
|
|
|
{
|
2012-08-28 09:20:30 +07:00
|
|
|
|
//TODO: We are pre-resolving the where into a ToList() here which will have performance impacts if there where clauses
|
|
|
|
|
|
// are nested! We should somehow support an QueryableDocumentList!
|
2012-10-04 01:31:08 +05:00
|
|
|
|
result = new DynamicPublishedContentList(this.OrderBy<DynamicPublishedContentBase>(args.First().ToString()).ToList());
|
2012-08-17 04:27:47 +06:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2012-08-28 09:20:30 +07:00
|
|
|
|
if (name == "Take")
|
|
|
|
|
|
{
|
2012-10-02 22:51:53 +05:00
|
|
|
|
result = new DynamicPublishedContentList(this.Take((int)args.First()));
|
2012-08-28 09:20:30 +07:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2012-08-28 09:33:34 +07:00
|
|
|
|
if (name == "Skip")
|
|
|
|
|
|
{
|
2012-10-02 22:51:53 +05:00
|
|
|
|
result = new DynamicPublishedContentList(this.Skip((int)args.First()));
|
2012-08-28 09:33:34 +07:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2012-08-28 09:20:30 +07:00
|
|
|
|
if (name == "InGroupsOf")
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
|
|
|
|
|
int groupSize = 0;
|
|
|
|
|
|
if (int.TryParse(args.First().ToString(), out groupSize))
|
|
|
|
|
|
{
|
2012-10-04 01:31:08 +05:00
|
|
|
|
result = this.InGroupsOf<DynamicPublishedContentBase>(groupSize);
|
2012-08-17 04:27:47 +06:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
result = new DynamicNull();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (name == "GroupedInto")
|
|
|
|
|
|
{
|
|
|
|
|
|
int groupCount = 0;
|
|
|
|
|
|
if (int.TryParse(args.First().ToString(), out groupCount))
|
|
|
|
|
|
{
|
2012-10-04 01:31:08 +05:00
|
|
|
|
result = this.GroupedInto<DynamicPublishedContentBase>(groupCount);
|
2012-08-17 04:27:47 +06:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
result = new DynamicNull();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (name == "GroupBy")
|
|
|
|
|
|
{
|
2012-10-04 01:31:08 +05:00
|
|
|
|
result = this.GroupBy<DynamicPublishedContentBase>(args.First().ToString());
|
2012-08-17 04:27:47 +06:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (name == "Average" || name == "Min" || name == "Max" || name == "Sum")
|
|
|
|
|
|
{
|
|
|
|
|
|
result = Aggregate(args, name);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (name == "Union")
|
|
|
|
|
|
{
|
2012-10-04 01:31:08 +05:00
|
|
|
|
if ((args.First() as IEnumerable<DynamicPublishedContentBase>) != null)
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
2012-10-04 01:31:08 +05:00
|
|
|
|
result = new DynamicPublishedContentList(this.Items.Union(args.First() as IEnumerable<DynamicPublishedContentBase>));
|
2012-08-17 04:27:47 +06:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2012-10-02 22:51:53 +05:00
|
|
|
|
if ((args.First() as DynamicPublishedContentList) != null)
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
2012-10-02 22:51:53 +05:00
|
|
|
|
result = new DynamicPublishedContentList(this.Items.Union((args.First() as DynamicPublishedContentList).Items));
|
2012-08-17 04:27:47 +06:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (name == "Except")
|
|
|
|
|
|
{
|
2012-10-04 01:31:08 +05:00
|
|
|
|
if ((args.First() as IEnumerable<DynamicPublishedContentBase>) != null)
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
2012-10-04 01:31:08 +05:00
|
|
|
|
result = new DynamicPublishedContentList(this.Items.Except(args.First() as IEnumerable<DynamicPublishedContentBase>, new DynamicPublishedContentIdEqualityComparer()));
|
2012-08-17 04:27:47 +06:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2012-10-02 22:51:53 +05:00
|
|
|
|
if ((args.First() as DynamicPublishedContentList) != null)
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
2012-10-02 22:51:53 +05:00
|
|
|
|
result = new DynamicPublishedContentList(this.Items.Except((args.First() as DynamicPublishedContentList).Items, new DynamicPublishedContentIdEqualityComparer()));
|
2012-08-17 04:27:47 +06:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (name == "Intersect")
|
|
|
|
|
|
{
|
2012-10-04 01:31:08 +05:00
|
|
|
|
if ((args.First() as IEnumerable<DynamicPublishedContentBase>) != null)
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
2012-10-04 01:31:08 +05:00
|
|
|
|
result = new DynamicPublishedContentList(this.Items.Intersect(args.First() as IEnumerable<DynamicPublishedContentBase>, new DynamicPublishedContentIdEqualityComparer()));
|
2012-08-17 04:27:47 +06:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2012-10-02 22:51:53 +05:00
|
|
|
|
if ((args.First() as DynamicPublishedContentList) != null)
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
2012-10-02 22:51:53 +05:00
|
|
|
|
result = new DynamicPublishedContentList(this.Items.Intersect((args.First() as DynamicPublishedContentList).Items, new DynamicPublishedContentIdEqualityComparer()));
|
2012-08-17 04:27:47 +06:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (name == "Distinct")
|
|
|
|
|
|
{
|
2012-10-02 22:51:53 +05:00
|
|
|
|
result = new DynamicPublishedContentList(this.Items.Distinct(new DynamicPublishedContentIdEqualityComparer()));
|
2012-08-17 04:27:47 +06:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (name == "Pluck" || name == "Select")
|
|
|
|
|
|
{
|
|
|
|
|
|
result = Pluck(args);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
//Property?
|
|
|
|
|
|
result = Items.GetType().InvokeMember(binder.Name,
|
|
|
|
|
|
System.Reflection.BindingFlags.Instance |
|
|
|
|
|
|
System.Reflection.BindingFlags.Public |
|
|
|
|
|
|
System.Reflection.BindingFlags.GetProperty,
|
|
|
|
|
|
null,
|
|
|
|
|
|
Items,
|
|
|
|
|
|
args);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (MissingMethodException)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
//Static or Instance Method?
|
|
|
|
|
|
result = Items.GetType().InvokeMember(binder.Name,
|
|
|
|
|
|
System.Reflection.BindingFlags.Instance |
|
|
|
|
|
|
System.Reflection.BindingFlags.Public |
|
|
|
|
|
|
System.Reflection.BindingFlags.Static |
|
|
|
|
|
|
System.Reflection.BindingFlags.InvokeMethod,
|
|
|
|
|
|
null,
|
|
|
|
|
|
Items,
|
|
|
|
|
|
args);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (MissingMethodException)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2012-08-22 08:33:19 +06:00
|
|
|
|
result = ExecuteExtensionMethod(args, name);
|
2012-08-17 04:27:47 +06:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (TargetInvocationException)
|
|
|
|
|
|
{
|
|
|
|
|
|
//We do this to enable error checking of Razor Syntax when a method e.g. ElementAt(2) is used.
|
|
|
|
|
|
//When the Script is tested, there's no Children which means ElementAt(2) is invalid (IndexOutOfRange)
|
|
|
|
|
|
//Instead, we are going to return an empty DynamicNode.
|
2012-10-04 01:31:08 +05:00
|
|
|
|
result = DynamicPublishedContentBase.Empty();
|
2012-08-17 04:27:47 +06:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
result = null;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
result = null;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
private T Aggregate<T>(List<T> data, string name) where T : struct
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (name)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "Min":
|
|
|
|
|
|
return data.Min<T>();
|
|
|
|
|
|
case "Max":
|
|
|
|
|
|
return data.Max<T>();
|
|
|
|
|
|
case "Average":
|
|
|
|
|
|
if (typeof(T) == typeof(int))
|
|
|
|
|
|
{
|
|
|
|
|
|
return (T)Convert.ChangeType((data as List<int>).Average(), typeof(T));
|
|
|
|
|
|
}
|
|
|
|
|
|
if (typeof(T) == typeof(decimal))
|
|
|
|
|
|
{
|
|
|
|
|
|
return (T)Convert.ChangeType((data as List<decimal>).Average(), typeof(T));
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "Sum":
|
|
|
|
|
|
if (typeof(T) == typeof(int))
|
|
|
|
|
|
{
|
|
|
|
|
|
return (T)Convert.ChangeType((data as List<int>).Sum(), typeof(T));
|
|
|
|
|
|
}
|
|
|
|
|
|
if (typeof(T) == typeof(decimal))
|
|
|
|
|
|
{
|
|
|
|
|
|
return (T)Convert.ChangeType((data as List<decimal>).Sum(), typeof(T));
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
return default(T);
|
|
|
|
|
|
}
|
|
|
|
|
|
private object Aggregate(object[] args, string name)
|
|
|
|
|
|
{
|
|
|
|
|
|
object result;
|
|
|
|
|
|
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
|
|
|
|
|
|
where g.Key != typeof(DynamicNull)
|
|
|
|
|
|
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))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new ArgumentException("Can only use aggregate methods on properties which are numeric");
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (dominantType == typeof(int))
|
|
|
|
|
|
{
|
|
|
|
|
|
List<int> data = (List<int>)itemsOfDominantTypeOnly.Cast<int>().ToList();
|
|
|
|
|
|
return Aggregate<int>(data, name);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (dominantType == typeof(decimal))
|
|
|
|
|
|
{
|
|
|
|
|
|
List<decimal> data = (List<decimal>)itemsOfDominantTypeOnly.Cast<decimal>().ToList();
|
|
|
|
|
|
return Aggregate<decimal>(data, name);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (dominantType == typeof(bool))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new ArgumentException("Can only use aggregate methods on properties which are numeric or datetime");
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (dominantType == typeof(DateTime))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (name != "Min" || name != "Max")
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new ArgumentException("Can only use aggregate min or max methods on properties which are datetime");
|
|
|
|
|
|
}
|
|
|
|
|
|
List<DateTime> data = (List<DateTime>)itemsOfDominantTypeOnly.Cast<DateTime>().ToList();
|
|
|
|
|
|
return Aggregate<DateTime>(data, name);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
result = query.ToList();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
private object Pluck(object[] args)
|
|
|
|
|
|
{
|
|
|
|
|
|
object result;
|
|
|
|
|
|
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 List<object>();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var types = from i in query
|
|
|
|
|
|
group i by i.GetType() into g
|
|
|
|
|
|
where g.Key != typeof(DynamicNull)
|
|
|
|
|
|
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 result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-08-22 08:33:19 +06:00
|
|
|
|
private object ExecuteExtensionMethod(object[] args, string name)
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
|
|
|
|
|
object result = null;
|
|
|
|
|
|
|
2012-08-22 08:33:19 +06:00
|
|
|
|
var methodTypesToFind = new[]
|
|
|
|
|
|
{
|
2012-10-04 01:31:08 +05:00
|
|
|
|
typeof(IEnumerable<DynamicPublishedContentBase>),
|
2012-10-02 22:51:53 +05:00
|
|
|
|
typeof(DynamicPublishedContentList)
|
2012-08-22 08:33:19 +06:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//find known extension methods that match the first type in the list
|
|
|
|
|
|
MethodInfo toExecute = null;
|
|
|
|
|
|
foreach(var t in methodTypesToFind)
|
|
|
|
|
|
{
|
|
|
|
|
|
toExecute = ExtensionMethodFinder.FindExtensionMethod(t, args, name, false);
|
|
|
|
|
|
if (toExecute != null)
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (toExecute != null)
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
2012-10-02 22:51:53 +05:00
|
|
|
|
if (toExecute.GetParameters().First().ParameterType == typeof(DynamicPublishedContentList))
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
|
|
|
|
|
var genericArgs = (new[] { this }).Concat(args);
|
2012-08-22 08:33:19 +06:00
|
|
|
|
result = toExecute.Invoke(null, genericArgs.ToArray());
|
2012-08-17 04:27:47 +06:00
|
|
|
|
}
|
2012-08-28 09:20:30 +07:00
|
|
|
|
else if (TypeHelper.IsTypeAssignableFrom<IQueryable>(toExecute.GetParameters().First().ParameterType))
|
|
|
|
|
|
{
|
|
|
|
|
|
//if it is IQueryable, we'll need to cast Items AsQueryable
|
|
|
|
|
|
var genericArgs = (new[] { Items.AsQueryable() }).Concat(args);
|
2012-08-22 08:33:19 +06:00
|
|
|
|
result = toExecute.Invoke(null, genericArgs.ToArray());
|
2012-08-28 09:20:30 +07:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var genericArgs = (new[] { Items }).Concat(args);
|
|
|
|
|
|
result = toExecute.Invoke(null, genericArgs.ToArray());
|
|
|
|
|
|
}
|
2012-08-17 04:27:47 +06:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new MissingMethodException();
|
|
|
|
|
|
}
|
|
|
|
|
|
if (result != null)
|
|
|
|
|
|
{
|
2012-10-02 01:35:39 +05:00
|
|
|
|
if (result is IPublishedContent)
|
2012-08-22 08:33:19 +06:00
|
|
|
|
{
|
2012-10-04 01:31:08 +05:00
|
|
|
|
result = new DynamicPublishedContentBase((IPublishedContent)result);
|
2012-08-22 08:33:19 +06:00
|
|
|
|
}
|
2012-10-02 01:35:39 +05:00
|
|
|
|
if (result is IEnumerable<IPublishedContent>)
|
2012-08-22 08:33:19 +06:00
|
|
|
|
{
|
2012-10-02 22:51:53 +05:00
|
|
|
|
result = new DynamicPublishedContentList((IEnumerable<IPublishedContent>)result);
|
2012-08-22 08:33:19 +06:00
|
|
|
|
}
|
2012-10-04 01:31:08 +05:00
|
|
|
|
if (result is IEnumerable<DynamicPublishedContentBase>)
|
2012-08-22 08:33:19 +06:00
|
|
|
|
{
|
2012-10-04 01:31:08 +05:00
|
|
|
|
result = new DynamicPublishedContentList((IEnumerable<DynamicPublishedContentBase>)result);
|
2012-08-22 08:33:19 +06:00
|
|
|
|
}
|
2012-08-17 04:27:47 +06:00
|
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IQueryable<T> Where<T>(string predicate, params object[] values)
|
|
|
|
|
|
{
|
|
|
|
|
|
return ((IQueryable<T>)Items.AsQueryable()).Where(predicate, values);
|
|
|
|
|
|
}
|
|
|
|
|
|
public IQueryable<T> OrderBy<T>(string key)
|
|
|
|
|
|
{
|
|
|
|
|
|
return ((IQueryable<T>)Items.AsQueryable()).OrderBy(key);
|
|
|
|
|
|
}
|
|
|
|
|
|
public DynamicGrouping GroupBy<T>(string key)
|
|
|
|
|
|
{
|
2012-08-28 09:20:30 +07:00
|
|
|
|
var group = new DynamicGrouping(this, key);
|
2012-08-17 04:27:47 +06:00
|
|
|
|
return group;
|
|
|
|
|
|
}
|
|
|
|
|
|
public DynamicGrouping GroupedInto<T>(int groupCount)
|
|
|
|
|
|
{
|
|
|
|
|
|
int groupSize = (int)Math.Ceiling(((decimal)Items.Count() / groupCount));
|
|
|
|
|
|
return new DynamicGrouping(
|
|
|
|
|
|
this
|
|
|
|
|
|
.Items
|
2012-10-04 01:31:08 +05:00
|
|
|
|
.Select((node, index) => new KeyValuePair<int, DynamicPublishedContentBase>(index, node))
|
2012-08-17 04:27:47 +06:00
|
|
|
|
.GroupBy(kv => (object)(kv.Key / groupSize))
|
2012-10-04 01:31:08 +05:00
|
|
|
|
.Select(item => new Grouping<object, DynamicPublishedContentBase>()
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
|
|
|
|
|
Key = item.Key,
|
|
|
|
|
|
Elements = item.Select(inner => inner.Value)
|
|
|
|
|
|
}));
|
|
|
|
|
|
}
|
|
|
|
|
|
public DynamicGrouping InGroupsOf<T>(int groupSize)
|
|
|
|
|
|
{
|
|
|
|
|
|
return new DynamicGrouping(
|
|
|
|
|
|
this
|
|
|
|
|
|
.Items
|
2012-10-04 01:31:08 +05:00
|
|
|
|
.Select((node, index) => new KeyValuePair<int, DynamicPublishedContentBase>(index, node))
|
2012-08-17 04:27:47 +06:00
|
|
|
|
.GroupBy(kv => (object)(kv.Key / groupSize))
|
2012-10-04 01:31:08 +05:00
|
|
|
|
.Select(item => new Grouping<object, DynamicPublishedContentBase>()
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
|
|
|
|
|
Key = item.Key,
|
|
|
|
|
|
Elements = item.Select(inner => inner.Value)
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IQueryable Select(string predicate, params object[] values)
|
|
|
|
|
|
{
|
2012-08-28 09:20:30 +07:00
|
|
|
|
return Items.AsQueryable().Select(predicate, values);
|
2012-08-17 04:27:47 +06:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-10-04 01:31:08 +05:00
|
|
|
|
public void Add(DynamicPublishedContentBase publishedContent)
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
2012-10-02 01:35:39 +05:00
|
|
|
|
this.Items.Add(publishedContent);
|
2012-08-17 04:27:47 +06:00
|
|
|
|
}
|
2012-10-04 01:31:08 +05:00
|
|
|
|
public void Remove(DynamicPublishedContentBase publishedContent)
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
2012-10-02 01:35:39 +05:00
|
|
|
|
if (this.Items.Contains(publishedContent))
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
2012-10-02 01:35:39 +05:00
|
|
|
|
this.Items.Remove(publishedContent);
|
2012-08-17 04:27:47 +06:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
public bool IsNull()
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
public bool HasValue()
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-10-04 01:31:08 +05:00
|
|
|
|
public IEnumerator<DynamicPublishedContentBase> GetEnumerator()
|
2012-08-17 04:27:47 +06:00
|
|
|
|
{
|
|
|
|
|
|
return Items.GetEnumerator();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
|
|
|
|
{
|
|
|
|
|
|
return GetEnumerator();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|