/// <summary> /// Apply orderby to the given resouce expression /// </summary> /// <param name="rootExpression"></param> /// <param name="entityInstanceType"></param> /// <param name="uriParser"></param> /// <param name="orderByClause"></param> /// <returns></returns> public static Expression ApplyOrderBy(this Expression rootExpression, Type entityInstanceType, ODataUriParser uriParser, OrderByClause orderByClause) { ParameterExpression parameter = Expression.Parameter(entityInstanceType, "it"); NodeToExpressionTranslator nodeToExpressionTranslator = new NodeToExpressionTranslator() { ImplicitVariableParameterExpression = parameter, UriParser = uriParser, }; Expression orderByNodeExpression = nodeToExpressionTranslator.TranslateNode(orderByClause.Expression); var keyType = EdmClrTypeUtils.GetInstanceType(orderByClause.Expression.TypeReference); if (orderByClause.Expression.TypeReference.IsNullable && keyType.IsValueType) { keyType = typeof(Nullable <>).MakeGenericType(keyType); } var method = orderByClause.Direction == OrderByDirection.Ascending ? "OrderBy" : "OrderByDescending"; //OrderBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector) var expression = Expression.Call( typeof(Enumerable), method, new Type[] { entityInstanceType, keyType }, rootExpression, Expression.Lambda(orderByNodeExpression, parameter)) as Expression; var thenBy = orderByClause.ThenBy; while (null != thenBy) { expression = expression.ApplyThenBy(entityInstanceType, uriParser, thenBy); thenBy = thenBy.ThenBy; } return(expression); }
/// <summary> /// Translate a single entity cast access to expression /// </summary> /// <param name="sourceNode">The source of single entity cast access.</param> /// <param name="typeReference">The target type reference of casting.</param> /// <returns></returns> private Expression TranslateSingleValueCastAccess(QueryNode sourceNode, IEdmTypeReference typeReference) { Expression source = this.TranslateNode(sourceNode); Type targetType = EdmClrTypeUtils.GetInstanceType(typeReference); return(Expression.TypeAs(source, targetType)); }
private Type GetElementTypeForOption(string option) { if (this.Target.ElementTypeKind == EdmTypeKind.None) { throw Utility.BuildException( HttpStatusCode.BadRequest, string.Format("The query option '{0}' can only be applied to collection resouces", option), null); } return(EdmClrTypeUtils.GetInstanceType(this.Target.ElementType.FullTypeName())); }
/// <summary> /// Translate KeySegment to linq expression. /// </summary> /// <param name="segment">The KeySegment</param> /// <returns>The linq expression</returns> public override Expression Translate(KeySegment segment) { if (!(this.LastProcessedSegment is EntitySetSegment || this.LastProcessedSegment is NavigationPropertySegment || this.LastProcessedSegment is NavigationPropertyLinkSegment)) { throw new InvalidOperationException("Unsupported URI segment before KeySegment"); } // translate to be ResultExpressionFromEntitySetSegment.Where(id -> id == keyVale).Single() IEdmEntityType entityType = segment.EdmType as IEdmEntityType; Type instanceType = EdmClrTypeUtils.GetInstanceType(entityType.FullTypeName()); // Convert to .Where(it=> it is Type) ParameterExpression parameter = Expression.Parameter(instanceType, "it"); Expression body = null; foreach (var key in segment.Keys) { Expression keyPredicate = null; var propertyAccessExpression = Expression.Property(parameter, instanceType, key.Key); var keyType = entityType.Key().Single(k => k.Name == key.Key).Type; if (keyType.IsTypeDefinition()) { var typeDefinition = keyType.AsTypeDefinition(); var underlyingType = EdmClrTypeUtils.GetInstanceType(typeDefinition.TypeDefinition().UnderlyingType.FullTypeName()); keyPredicate = Expression.Equal(Expression.Convert(propertyAccessExpression, underlyingType), Expression.Constant(key.Value)); } else { keyPredicate = Expression.Equal(propertyAccessExpression, Expression.Constant(key.Value)); } if (body == null) { body = keyPredicate; } else { body = Expression.AndAlso(body, keyPredicate); } } this.ResultExpression = Expression.Call( this.ResultExpression, typeof(EntityCollection <>).MakeGenericType(instanceType).GetMethod("GetEntity"), Expression.Lambda(body, parameter)); this.LastProcessedSegment = segment; return(this.ResultExpression); }
/// <summary> /// Visit a CountNode /// </summary> /// <param name="nodeIn">The node to visit</param> /// <returns>The translated expression</returns> public override Expression Visit(CountNode nodeIn) { this.CheckArgumentNull(nodeIn, "CountNode"); Type propType = null; Expression propExpr = null; // Element of collection could be primitive type or enum or complex or entity type if (nodeIn.Source.ItemType.IsPrimitive() || nodeIn.Source.ItemType.IsEnum()) { var collection = (CollectionPropertyAccessNode)nodeIn.Source; propExpr = Visit(collection); var def = collection.Property.Type.AsCollection(); propType = EdmClrTypeUtils.GetInstanceType(def.ElementType()); } else if ((nodeIn.Source.ItemType.IsComplex() && nodeIn.Source.Kind.Equals(QueryNodeKind.CollectionComplexNode))) { // This does not handle complex collection cast case, if it is a complex collection cast, the Kind will be CollectionComplexCast and node.Source is CollectionComplexCastNode var collection = (CollectionComplexNode)nodeIn.Source; propExpr = Visit(collection); var def = collection.Property.Type.AsCollection(); propType = EdmClrTypeUtils.GetInstanceType(def.ElementType()); } else if (nodeIn.Source.ItemType.IsEntity() && nodeIn.Source.Kind.Equals(QueryNodeKind.CollectionNavigationNode)) { // This does not handle entity collection cast case, if it is a entity collection cast, the Kind will be CollectionResourceCast and node.Source is CollectionResourceCastNode var collection = (CollectionNavigationNode)nodeIn.Source; propExpr = Visit(collection); var def = collection.NavigationProperty.Type.AsCollection(); propType = EdmClrTypeUtils.GetInstanceType(def.ElementType()); } else { // Should no such case as collection item is either primitive or enum or complex or entity. throw new NotSupportedException( string.Format( "Filter based on count of collection with item of type {0} is not supported yet.", nodeIn.Source.ItemType)); } // Per standard, collection can not be null, but could be an empty collection, so null is not considered here. var asQuerableMethod = _queryableAsQueryableMethod.MakeGenericMethod(propType); Expression asQuerableExpression = Expression.Call(null, asQuerableMethod, propExpr); var countMethod = _countMethod.MakeGenericMethod(propType); var countExpression = Expression.Call(null, countMethod, asQuerableExpression); return(countExpression); }
/// <summary> /// Visit a ConvertNode /// </summary> /// <param name="nodeIn">The node to visit</param> /// <returns>The translated expression</returns> public override Expression Visit(ConvertNode nodeIn) { this.CheckArgumentNull(nodeIn, "ConvertNode"); var sourceExpression = this.TranslateNode(nodeIn.Source); var targetEdmType = nodeIn.TypeReference; if (null == targetEdmType) { //Open property's target type is null, so return the source expression directly, supposely the caller should be ready to handle data of Object type. return(sourceExpression); } var targetClrType = EdmClrTypeUtils.GetInstanceType(targetEdmType); return(Expression.Convert(sourceExpression, targetClrType)); }
/// <summary> /// Translate CountSegment to linq expression. /// </summary> /// <param name="segment">The CountSegment</param> /// <returns>The linq expression</returns> public override Expression Translate(CountSegment segment) { if (!(this.LastProcessedSegment is EntitySetSegment || this.LastProcessedSegment is NavigationPropertySegment)) { throw new InvalidOperationException("Unsupported URI segment before CountSegment"); } Type instanceType = EdmClrTypeUtils.GetInstanceType((this.LastProcessedSegment.EdmType as EdmCollectionType).ElementType); // A set return now is a IEnumable, try to convert to IQueryable. this.ResultExpression = Expression.Call(typeof(Queryable), AsQueryableMethod, new Type[] { instanceType }, this.ResultExpression); this.ResultExpression = Expression.Call(typeof(Queryable), CountMethodName, new Type[] { instanceType }, this.ResultExpression); this.LastProcessedSegment = segment; return(this.ResultExpression); }
/// <summary> /// Visit a ConstantNode /// </summary> /// <param name="nodeIn">The node to visit</param> /// <returns>The translated expression</returns> public override Expression Visit(ConstantNode nodeIn) { this.CheckArgumentNull(nodeIn, "ConstantNode"); if (null == nodeIn.Value) { return(Expression.Constant(null)); } // collection of entity if (nodeIn.TypeReference != null && nodeIn.TypeReference.IsCollection() && (nodeIn.TypeReference.Definition as IEdmCollectionType).ElementType.IsEntity()) { return(Expression.Constant(ParseEntityCollection(nodeIn))); } // the value is entity or entity reference. if (nodeIn.TypeReference != null && nodeIn.TypeReference.IsEntity()) { return(Expression.Constant(ParseEntity(nodeIn))); } // the value is complex or collection. if (nodeIn.Value is ODataComplexValue || nodeIn.Value is ODataCollectionValue || nodeIn.Value is ODataEntry) { object value = ODataObjectModelConverter.ConvertPropertyValue(nodeIn.Value); return(Expression.Constant(value)); } // the value is enum if (nodeIn.TypeReference.IsEnum()) { ODataEnumValue enumValue = (ODataEnumValue)nodeIn.Value; object enumClrVal = Enum.Parse(EdmClrTypeUtils.GetInstanceType(enumValue.TypeName), enumValue.Value); return(Expression.Constant(enumClrVal, EdmClrTypeUtils.GetInstanceType(nodeIn.TypeReference))); } // the value is primitive Type targetType = nodeIn.Value.GetType(); if (nodeIn.TypeReference.IsSpatial()) { targetType = GetPublicSpatialBaseType(nodeIn.Value); } return(Expression.Constant(nodeIn.Value, targetType)); }
/// <summary> /// Translate TypeSegment to linq expression. /// </summary> /// <param name="segment">The TypeSegment</param> /// <returns>The linq expression</returns> public override Expression Translate(TypeSegment segment) { if (this.LastQueryTarget.IsEntitySet) { Type baseType = EdmClrTypeUtils.GetInstanceType(this.LastQueryTarget.ElementType.FullTypeName()); Type instanceType = EdmClrTypeUtils.GetInstanceType(((IEdmCollectionType)segment.EdmType).ElementType); // A set return now is a IEnumable, try to convert to IQueryable. this.ResultExpression = Expression.Call(typeof(Queryable), AsQueryableMethod, new Type[] { baseType }, this.ResultExpression); // Convert to .Where(it=> it is Type) ParameterExpression parameter = Expression.Parameter(baseType, "it"); Expression body = Expression.TypeIs(parameter, instanceType); this.ResultExpression = Expression.Call(typeof(Queryable), WhereMethodName, new Type[] { baseType }, this.ResultExpression, Expression.Quote(Expression.Lambda(body, parameter))); this.ResultExpression = Expression.Call(typeof(Queryable), CastMethodName, new[] { instanceType }, this.ResultExpression); } else if (this.LastQueryTarget.TypeKind == EdmTypeKind.Entity) { Type instanceType = EdmClrTypeUtils.GetInstanceType(segment.EdmType.FullTypeName()); this.ResultExpression = Expression.Convert(this.ResultExpression, instanceType); } else if (this.LastQueryTarget.Property != null) { if (this.LastQueryTarget.TypeKind == EdmTypeKind.Complex) { Type instanceType = EdmClrTypeUtils.GetInstanceType(segment.EdmType.FullTypeName()); this.ResultExpression = Expression.Convert(this.ResultExpression, instanceType); } else { // This code should not be hit. It should be prevented by UriParser. throw new ApplicationException( string.Format("PropertySegment with TypeKind '{0}' following by TypeSegment is invalid", this.LastQueryTarget.TypeKind)); } } else { throw Utility.BuildException(HttpStatusCode.NotImplemented, "Unsupported URI segment before TypeSegment", null); } this.LastProcessedSegment = segment; return(this.ResultExpression); }
/// <summary> /// Visit an AnyNode /// </summary> /// <param name="nodeIn">The node to visit</param> /// <returns>The translated expression</returns> public override Expression Visit(AnyNode nodeIn) { var instanceType = EdmClrTypeUtils.GetInstanceType(nodeIn.RangeVariables[0].TypeReference); ParameterExpression parameter = Expression.Parameter(instanceType, nodeIn.RangeVariables[0].Name); NodeToExpressionTranslator nodeToExpressionTranslator = new NodeToExpressionTranslator() { ImplicitVariableParameterExpression = parameter, UriParser = this.UriParser, DataSource = this.DataSource, }; Expression conditionExpression = nodeToExpressionTranslator.TranslateNode(nodeIn.Body); Expression rootExpression = this.TranslateNode(nodeIn.Source); return(Expression.Call( typeof(Enumerable), "Any", new Type[] { instanceType }, rootExpression, Expression.Lambda(conditionExpression, parameter))); }
/// <summary> /// Translate NavigationPropertyLinkSegment to linq expression. /// </summary> /// <param name="segment">The NavigationPropertyLinkSegment</param> /// <returns>The linq expression</returns> public override Expression Translate(NavigationPropertyLinkSegment segment) { if (!(this.LastProcessedSegment is KeySegment || this.LastProcessedSegment is SingletonSegment || this.LastProcessedSegment is TypeSegment)) { throw new InvalidOperationException("Unsupported URI segment before NavigationPropertyLinkSegment"); } var lastSegmentEntityType = this.LastProcessedSegment.EdmType as EdmEntityType; // <context>/PropertyName will be translated to <context>.PropertyName this.ResultExpression = Expression.Property( this.ResultExpression, EdmClrTypeUtils.GetInstanceType(lastSegmentEntityType.FullTypeName()), segment.NavigationProperty.Name); this.LastProcessedSegment = segment; return(this.ResultExpression); }
/// <summary> /// Handle an ExpandedReferenceSelectItem /// </summary> /// <param name="item">the item to Handle</param> public override void Handle(ExpandedReferenceSelectItem item) { var navigationProperty = (item.PathToNavigationProperty.LastSegment as NavigationPropertySegment).NavigationProperty; this.ExpandedChildElement = this.ParentElement.GetType().GetProperty(navigationProperty.Name).GetValue(this.ParentElement, null); if (this.ExpandedChildElement is IEnumerable) { var entityInstanceType = EdmClrTypeUtils.GetInstanceType(item.NavigationSource.EntityType().FullName()); Expression resultExpression = (this.ExpandedChildElement as IEnumerable).AsQueryable().Expression; if (item.FilterOption != null) { resultExpression = resultExpression.ApplyFilter(entityInstanceType, null, item.FilterOption); } if (item.SearchOption != null) { resultExpression = resultExpression.ApplySearch(entityInstanceType, null, item.SearchOption); } if (item.OrderByOption != null) { resultExpression = resultExpression.ApplyOrderBy(entityInstanceType, null, item.OrderByOption); } if (item.SkipOption.HasValue) { resultExpression = resultExpression.ApplySkip(entityInstanceType, item.SkipOption.Value); } if (item.TopOption.HasValue) { resultExpression = resultExpression.ApplyTop(entityInstanceType, item.TopOption.Value); } Expression <Func <object> > lambda = Expression.Lambda <Func <object> >(resultExpression); Func <object> compiled = lambda.Compile(); this.ExpandedChildElement = compiled() as IEnumerable; } }
/// <summary> /// Apply thenOrderBy to the given resouce expression /// </summary> /// <param name="rootExpression"></param> /// <param name="entityInstanceType"></param> /// <param name="uriParser"></param> /// <param name="thenBy"></param> /// <returns></returns> public static Expression ApplyThenBy(this Expression rootExpression, Type entityInstanceType, ODataUriParser uriParser, OrderByClause thenBy) { ParameterExpression parameter = Expression.Parameter(entityInstanceType, "it"); NodeToExpressionTranslator nodeToExpressionTranslator = new NodeToExpressionTranslator() { ImplicitVariableParameterExpression = parameter, UriParser = uriParser, }; Expression orderByNodeExpression = nodeToExpressionTranslator.TranslateNode(thenBy.Expression); var keyType = EdmClrTypeUtils.GetInstanceType(thenBy.Expression.TypeReference); var method = thenBy.Direction == OrderByDirection.Ascending ? "ThenBy" : "ThenByDescending"; //ThenBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector) return(Expression.Call( typeof(Enumerable), method, new Type[] { entityInstanceType, keyType }, rootExpression, Expression.Lambda(orderByNodeExpression, parameter))); }
public static object CreateResource(IEdmType type) { var targetType = EdmClrTypeUtils.GetInstanceType(type.FullTypeName()); return(QuickCreateInstance(targetType)); }
public static object ConvertPropertyValue(object propertyValue) { if (propertyValue == null) { return(null); } if (propertyValue is ODataEnumValue) { ODataEnumValue enumValue = (ODataEnumValue)propertyValue; return(Enum.Parse(EdmClrTypeUtils.GetInstanceType(enumValue.TypeName), enumValue.Value)); } if (propertyValue is ODataCollectionValue) { ODataCollectionValue collection = (ODataCollectionValue)propertyValue; IList collectionList = null; foreach (object odataItem in collection.Items) { var item = ConvertPropertyValue(odataItem); if (collectionList == null) { Type listType = string.IsNullOrEmpty(collection.TypeName) ? null : EdmClrTypeUtils.GetInstanceType(collection.TypeName); if (listType == null) { Type itemType = item.GetType(); listType = typeof(List <>).MakeGenericType(new[] { itemType }); } collectionList = (IList)Utility.QuickCreateInstance(listType); } collectionList.Add(item); } return(collectionList); } if (propertyValue is ODataResource) { ODataResource entry = (ODataResource)propertyValue; var type = EdmClrTypeUtils.GetInstanceType(entry.TypeName); var newInstance = Utility.QuickCreateInstance(type); foreach (var p in entry.Properties) { PropertyInfo targetProperty = type.GetProperty(p.Name); // If the value is a odata collection value that contains no element, set the value to a empty collection. // ConvertPropertyValue won't work here because it could not know what the type it its. var collectionValue = p.Value as ODataCollectionValue; if (collectionValue != null && !collectionValue.Items.Cast <object>().Any()) { targetProperty.SetValue(newInstance, Utility.QuickCreateInstance(targetProperty.PropertyType), new object[] { }); } else { targetProperty.SetValue(newInstance, ConvertPropertyValue(p.Value), new object[] { }); } } return(newInstance); } return(propertyValue); }
public static object ReadEntityOrEntityCollection(ODataReader reader, bool forFeed) { MethodInfo addMethod = null; // Store the last entry of the top-level feed or the top-level entry; ODataResource entry = null; // Store entries at each level Stack <ODataItem> items = new Stack <ODataItem>(); // Store the objects with its parent for current level. // Example: // CompleCollection: [ complex1, complex2 ] // objects contains [{CompleCollection, complex1Obj}, {CompleCollection, complex2Obj}] when NestedResourceInfoEnd for CompleCollection Stack <KeyValuePair <ODataItem, object> > objects = new Stack <KeyValuePair <ODataItem, object> >(); // Store the SetValue action for complex property. Stack <KeyValuePair <ODataItem, Action <object> > > actions = new Stack <KeyValuePair <ODataItem, Action <object> > >(); while (reader.Read()) { switch (reader.State) { case ODataReaderState.ResourceStart: case ODataReaderState.NestedResourceInfoStart: { items.Push(reader.Item); break; } case ODataReaderState.NestedResourceInfoEnd: { items.Pop(); // Create current complex property value. var currentProperty = reader.Item as ODataNestedResourceInfo; var parent = items.Peek() as ODataResource; var parentType = EdmClrTypeUtils.GetInstanceType(parent.TypeName); var propertyInfo = parentType.GetProperty(currentProperty.Name); if (propertyInfo != null) { var propertyType = propertyInfo.PropertyType; if (propertyType.IsGenericType) { Type listType = typeof(List <>).MakeGenericType(propertyType.GetGenericArguments()[0]); addMethod = listType.GetMethod("Add"); var currentList = Activator.CreateInstance(listType); while (objects.Count > 0 && objects.Peek().Key == currentProperty) { addMethod.Invoke(currentList, new[] { objects.Pop().Value }); } // Keep the order of all the items MethodInfo reverseMethod = listType.GetMethod("Reverse", new Type[0]); reverseMethod.Invoke(currentList, new object[0]); actions.Push(new KeyValuePair <ODataItem, Action <object> >(parent, obj => propertyInfo.SetValue(obj, currentList))); } else { var propertyValue = objects.Pop().Value; actions.Push(new KeyValuePair <ODataItem, Action <object> >(parent, obj => propertyInfo.SetValue(obj, propertyValue))); } } break; } case ODataReaderState.ResourceEnd: { // Create object for current resource. entry = reader.Item as ODataResource; object item = ODataObjectModelConverter.ConvertPropertyValue(entry); while (actions.Count > 0 && actions.Peek().Key == entry) { actions.Pop().Value.Invoke(item); } items.Pop(); var parent = items.Count > 0 ? items.Peek() : null; objects.Push(new KeyValuePair <ODataItem, object>(parent, item)); break; } default: break; } } if (forFeed) { // create the list. This would require the first type is not derived type. List <object> topLeveObjects = new List <object>(); while (objects.Count > 0) { topLeveObjects.Add(objects.Pop().Value); } Type type = null; // Need to fix this if all items in the collection are null; if (entry == null || string.IsNullOrEmpty(entry.TypeName)) { for (int i = 0; i < topLeveObjects.Count; i++) { if (topLeveObjects[i] != null) { type = topLeveObjects[i].GetType(); break; } } } else { type = EdmClrTypeUtils.GetInstanceType(entry.TypeName); } Type listType = typeof(List <>).MakeGenericType(type); addMethod = listType.GetMethod("Add"); var list = Activator.CreateInstance(listType); for (int i = topLeveObjects.Count - 1; i >= 0; i--) { addMethod.Invoke(list, new[] { topLeveObjects[i] }); } return(list); } else { return(objects.Pop().Value); } }
/// <summary> /// Parse the constant entity collection node. /// </summary> /// <param name="nodeIn">The input constant node.</param> /// <returns>The parsed object.</returns> private object ParseEntityCollection(ConstantNode nodeIn) { ODataMessageReaderSettings settings = new ODataMessageReaderSettings(); InMemoryMessage message = new InMemoryMessage() { Stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(nodeIn.LiteralText)), }; var entityType = ((nodeIn.TypeReference.Definition as IEdmCollectionType).ElementType as IEdmEntityTypeReference) .Definition as IEdmEntityType; object list = null; MethodInfo addMethod = null; using ( ODataMessageReader reader = new ODataMessageReader(message as IODataRequestMessage, settings, this.UriParser.Model)) { if (nodeIn.LiteralText.Contains("@odata.id")) { ODataEntityReferenceLinks referenceLinks = reader.ReadEntityReferenceLinks(); foreach (var referenceLink in referenceLinks.Links) { var queryContext = new QueryContext(this.UriParser.ServiceRoot, referenceLink.Url, this.DataSource.Model); var target = queryContext.ResolveQuery(this.DataSource); if (list == null) { // create the list. This would require the first type is not derived type. Type listType = typeof(List <>).MakeGenericType(target.GetType()); addMethod = listType.GetMethod("Add"); list = Activator.CreateInstance(listType); } addMethod.Invoke(list, new[] { target }); } return(list); } var feedReader = reader.CreateODataFeedReader( new EdmEntitySet(new EdmEntityContainer("NS", "Test"), "TestType", entityType), entityType); ODataEntry entry = null; while (feedReader.Read()) { if (feedReader.State == ODataReaderState.EntryEnd) { entry = feedReader.Item as ODataEntry; object item = ODataObjectModelConverter.ConvertPropertyValue(entry); if (list == null) { // create the list. This would require the first type is not derived type. var type = EdmClrTypeUtils.GetInstanceType(entry.TypeName); Type listType = typeof(List <>).MakeGenericType(type); addMethod = listType.GetMethod("Add"); list = Activator.CreateInstance(listType); } addMethod.Invoke(list, new[] { item }); } } return(list); } }
/// <summary> /// Translates a function call into a corresponding <see cref="Expression"/>. /// </summary> /// <param name="functionName">Name of the function.</param> /// <param name="argumentNodes">The argument nodes.</param> /// <returns> /// The translated expression. /// </returns> private Expression TranslateFunctionCall(string functionName, IEnumerable <QueryNode> argumentNodes) { switch (functionName) { #region string functions case "contains": var methodInfoOfContains = typeof(string).GetMethod("Contains", BindingFlags.Public | BindingFlags.Instance); var instanceOfContains = argumentNodes.ElementAt(0).Accept(this); var argumentOfContains = argumentNodes.ElementAt(1).Accept(this); return(Expression.Call(instanceOfContains, methodInfoOfContains, argumentOfContains)); case "endswith": var methodInfoOfEndsWith = typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) }); var instanceOfEndsWith = argumentNodes.ElementAt(0).Accept(this); var argumentOfEndsWith = argumentNodes.ElementAt(1).Accept(this); return(Expression.Call(instanceOfEndsWith, methodInfoOfEndsWith, argumentOfEndsWith)); case "startswith": var methodInfoOfStartsWith = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) }); var instanceOfStartsWith = argumentNodes.ElementAt(0).Accept(this); var argumentOfStartsWith = argumentNodes.ElementAt(1).Accept(this); return(Expression.Call(instanceOfStartsWith, methodInfoOfStartsWith, argumentOfStartsWith)); case "length": var propertyInfoOfLength = typeof(string).GetProperty("Length", typeof(int)); var instanceOfLength = argumentNodes.ElementAt(0).Accept(this); return(Expression.Property(instanceOfLength, propertyInfoOfLength)); case "indexof": var methodInfoOfIndexOf = typeof(string).GetMethod("IndexOf", new Type[] { typeof(string) }); var instanceOfIndexOf = argumentNodes.ElementAt(0).Accept(this); var argumentOfIndexOf = argumentNodes.ElementAt(1).Accept(this); return(Expression.Call(instanceOfIndexOf, methodInfoOfIndexOf, argumentOfIndexOf)); case "substring": var argumentCount = argumentNodes.Count(); if (argumentNodes.Count() == 2) { var methodInfoOfSubString = typeof(string).GetMethod("Substring", new Type[] { typeof(int) }); var instanceOfSubString = argumentNodes.ElementAt(0).Accept(this); var argumentOfSubString = argumentNodes.ElementAt(1).Accept(this); return(Expression.Call(instanceOfSubString, methodInfoOfSubString, argumentOfSubString)); } else if (argumentNodes.Count() == 3) { var methodInfoOfSubString = typeof(string).GetMethod("Substring", new Type[] { typeof(int), typeof(int) }); var instanceOfSubString = argumentNodes.ElementAt(0).Accept(this); var argumentOfSubString = argumentNodes.ElementAt(1).Accept(this); var argumentOfSubString2 = argumentNodes.ElementAt(2).Accept(this); return(Expression.Call(instanceOfSubString, methodInfoOfSubString, argumentOfSubString, argumentOfSubString2)); } else { throw new ArgumentException("argumentNodes"); } case "tolower": var methodInfoOfToLower = typeof(string).GetMethod("ToLower", new Type[] { }); var instanceOfToLower = argumentNodes.ElementAt(0).Accept(this); return(Expression.Call(instanceOfToLower, methodInfoOfToLower)); case "toupper": var methodInfoOfToUpper = typeof(string).GetMethod("ToUpper", new Type[] { }); var instanceOfToUpper = argumentNodes.ElementAt(0).Accept(this); return(Expression.Call(instanceOfToUpper, methodInfoOfToUpper)); case "trim": var methodInfoOfTrim = typeof(string).GetMethod("Trim", new Type[] { }); var instanceOfTrim = argumentNodes.ElementAt(0).Accept(this); return(Expression.Call(instanceOfTrim, methodInfoOfTrim)); case "concat": var methodInfoOfConcat = typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string) }); var argumentOfConcat1 = argumentNodes.ElementAt(0).Accept(this); var argumentOfConcat2 = argumentNodes.ElementAt(1).Accept(this); return(Expression.Call(methodInfoOfConcat, argumentOfConcat1, argumentOfConcat2)); #endregion #region DateTime Method case "year": return(TranslateDateTimeInstanceProperty("Year", argumentNodes)); case "month": return(TranslateDateTimeInstanceProperty("Month", argumentNodes)); case "day": return(TranslateDateTimeInstanceProperty("Day", argumentNodes)); case "hour": return(TranslateDateTimeInstanceProperty("Hour", argumentNodes)); case "minute": return(TranslateDateTimeInstanceProperty("Minute", argumentNodes)); case "second": return(TranslateDateTimeInstanceProperty("Second", argumentNodes)); // Don't support those type by now. //case "fractionalseconds": // return TranslateDateTimeInstanceProperty("Millisecond", argumentNodes); //case "date": // return TranslateDateTimeInstanceProperty("Date", argumentNodes); //case "time": // return TranslateDateTimeProperty("Year"); //case "totaloffsetminutes": // return TranslateDateTimeProperty("Date", argumentNodes); //case "now": // return TranslateDateTimeProperty("Now", argumentNodes); //case "mindatetime": // return TranslateDateTimeProperty("MinValue", argumentNodes); //case "maxdatetime": // return TranslateDateTimeProperty("MaxValue", argumentNodes); #endregion #region Math Methods case "round": return(TranslateMathFunction("Round", argumentNodes)); case "floor": return(TranslateMathFunction("Floor", argumentNodes)); case "ceiling": return(TranslateMathFunction("Ceiling", argumentNodes)); #endregion #region Type Functions case "cast": var instanceOfCast = argumentNodes.ElementAt(0).Accept(this); var typeInfoOfCast = (ConstantNode)argumentNodes.ElementAt(1); var targetTypeOfCast = EdmClrTypeUtils.GetInstanceType(typeInfoOfCast.Value.ToString()); var methodInfoOfCast = typeof(TypeFunctionHelper).GetMethod("TypeCastFunction", BindingFlags.Public | BindingFlags.Static); methodInfoOfCast = methodInfoOfCast.MakeGenericMethod(new Type[] { targetTypeOfCast, instanceOfCast.Type }); return(Expression.Call(methodInfoOfCast, instanceOfCast)); case "isof": var instanceOfIsOf = argumentNodes.ElementAt(0).Accept(this); var typeInfoOfIsOf = (ConstantNode)argumentNodes.ElementAt(1); return(Expression.TypeIs(instanceOfIsOf, EdmClrTypeUtils.GetInstanceType(typeInfoOfIsOf.Value.ToString()))); #endregion #region Geo Functions case "geo.distance": var argumentOfGeoDistance1 = argumentNodes.ElementAt(0).Accept(this); var argumentOfGeoDistance2 = argumentNodes.ElementAt(1).Accept(this); var methodInfoOfGeoDistance = typeof(GeoFunctionHelper) .GetMethod("GetDistance", new Type[] { argumentOfGeoDistance1.Type, argumentOfGeoDistance2.Type }); return(Expression.Call(methodInfoOfGeoDistance, argumentOfGeoDistance1, argumentOfGeoDistance2)); case "geo.length": var argumentOfGeoLength = argumentNodes.ElementAt(0).Accept(this); var methodInfoOfGeoLength = typeof(GeoFunctionHelper) .GetMethod("GetLength", new Type[] { argumentOfGeoLength.Type }); return(Expression.Call(methodInfoOfGeoLength, argumentOfGeoLength)); case "geo.intersects": var argumentOfGeoIntersects1 = argumentNodes.ElementAt(0).Accept(this); var argumentOfGeoIntersects2 = argumentNodes.ElementAt(1).Accept(this); var methodInfoOfGeoIntersectse = typeof(GeoFunctionHelper) .GetMethod("GetIsIntersects", new Type[] { argumentOfGeoIntersects1.Type, argumentOfGeoIntersects2.Type }); return(Expression.Call(methodInfoOfGeoIntersectse, argumentOfGeoIntersects1, argumentOfGeoIntersects2)); #endregion default: throw new ArgumentException(functionName); } }