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); }
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) { var name = binder.Name; if (name == "Where") { string predicate = args.First().ToString(); var values = args.Skip(1).ToArray(); result = new DynamicNodeList(this.Where <DynamicNode>(predicate, values).ToList()); return(true); } if (name == "OrderBy") { result = new DynamicNodeList(this.OrderBy <DynamicNode>(args.First().ToString()).ToList()); return(true); } if (name == "InGroupsOf") { int groupSize = 0; if (int.TryParse(args.First().ToString(), out groupSize)) { result = this.InGroupsOf <DynamicNode>(groupSize); return(true); } result = new DynamicNull(); return(true); } if (name == "GroupedInto") { int groupCount = 0; if (int.TryParse(args.First().ToString(), out groupCount)) { result = this.GroupedInto <DynamicNode>(groupCount); return(true); } result = new DynamicNull(); return(true); } if (name == "GroupBy") { result = this.GroupBy <DynamicNode>(args.First().ToString()); return(true); } if (name == "Average" || name == "Min" || name == "Max" || name == "Sum") { result = Aggregate(args, name); return(true); } if (name == "Union") { if ((args.First() as IEnumerable <DynamicNode>) != null) { result = new DynamicNodeList(this.Items.Union(args.First() as IEnumerable <DynamicNode>)); return(true); } if ((args.First() as DynamicNodeList) != null) { result = new DynamicNodeList(this.Items.Union((args.First() as DynamicNodeList).Items)); return(true); } } if (name == "Except") { if ((args.First() as IEnumerable <DynamicNode>) != null) { result = new DynamicNodeList(this.Items.Except(args.First() as IEnumerable <DynamicNode>, new DynamicNodeIdEqualityComparer())); return(true); } if ((args.First() as DynamicNodeList) != null) { result = new DynamicNodeList(this.Items.Except((args.First() as DynamicNodeList).Items, new DynamicNodeIdEqualityComparer())); return(true); } } if (name == "Intersect") { if ((args.First() as IEnumerable <DynamicNode>) != null) { result = new DynamicNodeList(this.Items.Intersect(args.First() as IEnumerable <DynamicNode>, new DynamicNodeIdEqualityComparer())); return(true); } if ((args.First() as DynamicNodeList) != null) { result = new DynamicNodeList(this.Items.Intersect((args.First() as DynamicNodeList).Items, new DynamicNodeIdEqualityComparer())); return(true); } } if (name == "Distinct") { result = new DynamicNodeList(this.Items.Distinct(new DynamicNodeIdEqualityComparer())); 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.NonPublic | 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.NonPublic | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.InvokeMethod, null, Items, args); return(true); } catch (MissingMethodException) { try { result = ExecuteExtensionMethod(args, name, false); 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. result = new DynamicNode(); return(true); } catch { result = null; return(false); } } } catch { result = null; return(false); } }
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { var name = binder.Name; if (name == "Where") { string predicate = args.First().ToString(); var values = args.Skip(1).ToArray(); result = new DynamicNodeList(this.Where <DynamicNode>(predicate, values).ToList()); return(true); } if (name == "OrderBy") { 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? result = Items.GetType().InvokeMember(binder.Name, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | 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.NonPublic | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.InvokeMethod, null, Items, args); return(true); } catch (MissingMethodException) { try { result = ExecuteExtensionMethod(args, name, false); 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. result = new DynamicNode(); return(true); } catch { result = null; return(false); } } } catch { result = null; return(false); } }
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { var firstArg = args.FirstOrDefault(); //this is to check for 'DocumentTypeAlias' vs 'NodeTypeAlias' for compatibility if (firstArg != null && firstArg.ToString().InvariantStartsWith("DocumentTypeAlias")) { firstArg = "NodeTypeAlias" + firstArg.ToString().Substring("DocumentTypeAlias".Length); } var name = binder.Name; if (name == "Single") { string predicate = firstArg == null ? "" : firstArg.ToString(); var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray(); var single = this.Single <DynamicNode>(predicate, values); result = new DynamicNode(single); return(true); } if (name == "SingleOrDefault") { string predicate = firstArg == null ? "" : firstArg.ToString(); var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray(); var single = this.SingleOrDefault <DynamicNode>(predicate, values); if (single == null) { result = new DynamicNull(); } else { result = new DynamicNode(single); } return(true); } if (name == "First") { string predicate = firstArg == null ? "" : firstArg.ToString(); var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray(); var first = this.First <DynamicNode>(predicate, values); result = new DynamicNode(first); return(true); } if (name == "FirstOrDefault") { string predicate = firstArg == null ? "" : firstArg.ToString(); var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray(); var first = this.FirstOrDefault <DynamicNode>(predicate, values); if (first == null) { result = new DynamicNull(); } else { result = new DynamicNode(first); } return(true); } if (name == "Last") { string predicate = firstArg == null ? "" : firstArg.ToString(); var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray(); var last = this.Last <DynamicNode>(predicate, values); result = new DynamicNode(last); return(true); } if (name == "LastOrDefault") { string predicate = firstArg == null ? "" : firstArg.ToString(); var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray(); var last = this.LastOrDefault <DynamicNode>(predicate, values); if (last == null) { result = new DynamicNull(); } else { result = new DynamicNode(last); } return(true); } if (name == "Where") { string predicate = firstArg.ToString(); var values = args.Skip(1).ToArray(); result = new DynamicNodeList(this.Where <DynamicNode>(predicate, values).ToList()); return(true); } if (name == "OrderBy") { result = new DynamicNodeList(this.OrderBy <DynamicNode>(firstArg.ToString()).ToList()); return(true); } if (name == "Take") { result = new DynamicNodeList(this.Take((int)firstArg)); return(true); } if (name == "Skip") { result = new DynamicNodeList(this.Skip((int)firstArg)); return(true); } if (name == "InGroupsOf") { int groupSize = 0; if (int.TryParse(firstArg.ToString(), out groupSize)) { result = this.InGroupsOf <DynamicNode>(groupSize); return(true); } result = new DynamicNull(); return(true); } if (name == "GroupedInto") { int groupCount = 0; if (int.TryParse(firstArg.ToString(), out groupCount)) { result = this.GroupedInto <DynamicNode>(groupCount); return(true); } result = new DynamicNull(); return(true); } if (name == "GroupBy") { result = this.GroupBy <DynamicNode>(firstArg.ToString()); return(true); } if (name == "Average" || name == "Min" || name == "Max" || name == "Sum") { result = Aggregate(args, name); return(true); } if (name == "Union") { if ((firstArg as IEnumerable <DynamicNode>) != null) { result = new DynamicNodeList(this.Items.Union(firstArg as IEnumerable <DynamicNode>)); return(true); } if ((firstArg as DynamicNodeList) != null) { result = new DynamicNodeList(this.Items.Union((firstArg as DynamicNodeList).Items)); return(true); } } if (name == "Except") { if ((firstArg as IEnumerable <DynamicNode>) != null) { result = new DynamicNodeList(this.Items.Except(firstArg as IEnumerable <DynamicNode>, new DynamicNodeIdEqualityComparer())); return(true); } if ((firstArg as DynamicNodeList) != null) { result = new DynamicNodeList(this.Items.Except((firstArg as DynamicNodeList).Items, new DynamicNodeIdEqualityComparer())); return(true); } } if (name == "Intersect") { if ((firstArg as IEnumerable <DynamicNode>) != null) { result = new DynamicNodeList(this.Items.Intersect(firstArg as IEnumerable <DynamicNode>, new DynamicNodeIdEqualityComparer())); return(true); } if ((firstArg as DynamicNodeList) != null) { result = new DynamicNodeList(this.Items.Intersect((firstArg as DynamicNodeList).Items, new DynamicNodeIdEqualityComparer())); return(true); } } if (name == "Distinct") { result = new DynamicNodeList(this.Items.Distinct(new DynamicNodeIdEqualityComparer())); 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 { result = ExecuteExtensionMethod(args, name, false); 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. result = new DynamicNode(); return(true); } catch { result = null; return(false); } } } catch { result = null; return(false); } }
public override bool TryGetMember(GetMemberBinder binder, out object result) { var name = binder.Name; result = null; //this will never be returned if (name == "ChildrenAsList" || name == "Children") { result = GetChildrenAsList; return(true); } bool propertyExists = false; if (n != null) { var data = n.GetProperty(name, out propertyExists); // check for nicer support of Pascal Casing EVEN if alias is camelCasing: if (data == null && name.Substring(0, 1).ToUpper() == name.Substring(0, 1) && !propertyExists) { data = n.GetProperty(name.Substring(0, 1).ToLower() + name.Substring((1)), out propertyExists); } if (data != null) { result = data.Value; //special casing for true/false properties //int/decimal are handled by ConvertPropertyValueByDataType //fallback is stringT Guid dataType = ContentType.GetDataType(n.NodeTypeAlias, data.Alias); //convert the string value to a known type return(ConvertPropertyValueByDataType(ref result, name, dataType)); } //check if the alias is that of a child type var typeChildren = n.ChildrenAsList .Where(x => MakePluralName(x.NodeTypeAlias) == name || x.NodeTypeAlias == name); if (typeChildren.Any()) { result = new DynamicNodeList(typeChildren); return(true); } try { result = n.GetType().InvokeMember(binder.Name, System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic, null, n, null); return(true); } catch { //result = null; //return false; } } //if property access, type lookup and member invoke all failed //at this point, we're going to return null //instead, we return a DynamicNull - see comments in that file //this will let things like Model.ChildItem work and return nothing instead of crashing if (!propertyExists && result == null) { //.Where explictly checks for this type //and will make it false //which means backwards equality (&& property != true) will pass //forwwards equality (&& property or && property == true) will fail result = new DynamicNull(); return(true); } return(true); }