public void TranslatorShouldTranslateCastFunctionCallWithTwoParameters() { ConstantNode constantNode; this.testSubject = this.CreateTestSubjectWithEdmStringLiteral(out constantNode); this.TestFunctionCall <object, string>("cast", new[] { Parameter <object>("o"), constantNode }, o => (string)o, this.testSubject); }
private NodeToExpressionTranslator CreateTestSubject( DataServiceBehavior dataServiceBehavior = null, FunctionExpressionBinder expressionBinder = null, Action <ODataProtocolVersion> verifyProtocolVersion = null, Action <ODataProtocolVersion> verifyRequestVersion = null) { if (dataServiceBehavior == null) { dataServiceBehavior = new DataServiceBehavior(); } if (expressionBinder == null) { expressionBinder = this.functionExpressionBinder; } if (verifyProtocolVersion == null) { verifyProtocolVersion = v => { }; } if (verifyRequestVersion == null) { verifyRequestVersion = v => { }; } return(NodeToExpressionTranslator.CreateForTests( expressionBinder, dataServiceBehavior, new object(), false, this.implicitParameterExpression, verifyProtocolVersion, verifyRequestVersion)); }
public void TranslatorShouldTranslateIsOfFunctionCallWithTwoParameters() { ConstantNode constantNode; this.testSubject = this.CreateTestSubjectWithEdmStringLiteral(out constantNode); this.TestFunctionCall <object, bool>("isof", new[] { Parameter <object>("o"), constantNode }, o => o is string, this.testSubject); }
public void TranslatorShouldTranslateReplaceIfEnabled() { this.testSubject = this.CreateTestSubject(new DataServiceBehavior { AcceptReplaceFunctionInQuery = true }); this.TestFunctionCall <string, string>("replace", new[] { Parameter <string>("s"), Constant("foo"), Constant("bar") }, s => s.Replace("foo", "bar"), this.testSubject); }
public void TranslatorShouldRequireProtocolVersionThreeForSingletonTypeSegment() { ODataProtocolVersion validatedProtocolVersion = ODataProtocolVersion.V4; this.testSubject = this.CreateTestSubject(verifyProtocolVersion: v => { validatedProtocolVersion = v; }, verifyRequestVersion: v => { throw new Exception("Should not be called."); }); QueryNode node = new SingleResourceCastNode(this.EntityParameter <Customer>("o"), this.customerEdmType); this.testSubject.TranslateNode(node); validatedProtocolVersion.Should().Be(ODataProtocolVersion.V4); }
public void TranslatorShouldRequireProtocolAndRequestVersionThreeForAnyAndAll() { ODataProtocolVersion validatedProtocolVersion = ODataProtocolVersion.V4; ODataProtocolVersion validatedRequestVersion = ODataProtocolVersion.V4; this.testSubject = this.CreateTestSubject(verifyProtocolVersion: v => { validatedProtocolVersion = v; }, verifyRequestVersion: v => { validatedRequestVersion = v; }); LambdaNode node = new AnyNode(new Collection <RangeVariable>(), null); node.Body = Constant(true); node.Source = this.CollectionNavigationFromParameter("o"); this.testSubject.TranslateNode(node); validatedProtocolVersion.Should().Be(ODataProtocolVersion.V4); validatedRequestVersion.Should().Be(ODataProtocolVersion.V4); }
/// <summary> /// Apply filter to the given resouce expression /// </summary> /// <param name="rootExpression"></param> /// <param name="entityInstanceType"></param> /// <param name="uriParser"></param> /// <param name="filterClause"></param> /// <returns></returns> public static Expression ApplyFilter(this Expression rootExpression, Type entityInstanceType, ODataUriParser uriParser, FilterClause filterClause) { ParameterExpression parameter = Expression.Parameter(entityInstanceType, "it"); NodeToExpressionTranslator nodeToExpressionTranslator = new NodeToExpressionTranslator() { ImplicitVariableParameterExpression = parameter, UriParser = uriParser, }; Expression filterNodeExpression = nodeToExpressionTranslator.TranslateNode(filterClause.Expression); // IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate); // translate to rootExpression.Where(filterNodeExpression) return Expression.Call( typeof(Enumerable), "Where", new Type[] { entityInstanceType }, rootExpression, Expression.Lambda(filterNodeExpression, parameter)); }
/// <summary>Filters a query like a SQL WHERE clause does.</summary> /// <param name="service">Service with data and configuration.</param> /// <param name="requestDescription">RequestDescription instance containing information about the current request being parsed.</param> /// <param name="source">Original source for query expression.</param> /// <returns>The composed query expression.</returns> internal static Expression Where(IDataService service, RequestDescription requestDescription, Expression source) { Debug.Assert(service != null, "service != null"); Debug.Assert(source != null, "source != null"); Debug.Assert(requestDescription != null, "requestDescription != null"); FilterClause filterClause = new RequestExpressionParser(service, requestDescription).ParseFilter(); if (filterClause == null) { return(source); } bool filterQueryApplicable = requestDescription.TargetKind == RequestTargetKind.Resource || requestDescription.TargetKind == RequestTargetKind.OpenProperty || requestDescription.TargetKind == RequestTargetKind.ComplexObject || requestDescription.CountOption == RequestQueryCountOption.CountSegment; if (!filterQueryApplicable) { throw DataServiceException.CreateBadRequestError(Strings.RequestQueryProcessor_QueryFilterOptionNotApplicable); } Type queryElementType = source.ElementType(); Debug.Assert(queryElementType != null, "queryElementType != null"); ParameterExpression parameterForIt = Expression.Parameter(queryElementType, "it"); Debug.Assert( (requestDescription.TargetResourceSet == null && (requestDescription.TargetResourceType == null || requestDescription.TargetResourceType.ResourceTypeKind != ResourceTypeKind.EntityType)) || (requestDescription.TargetResourceType != null && requestDescription.TargetResourceType.ResourceTypeKind == ResourceTypeKind.EntityType), "setForIt cannot be null if typeForIt is an entity type."); Debug.Assert( requestDescription.TargetResourceType == null && parameterForIt.Type == typeof(object) || requestDescription.TargetResourceType != null && requestDescription.TargetResourceType.InstanceType == parameterForIt.Type, "non-open type expressions should have a typeForIt"); var translator = NodeToExpressionTranslator.Create(service, requestDescription, parameterForIt); LambdaExpression lambda = translator.TranslateFilterClause(filterClause); return(source.QueryableWhere(lambda)); }
/// <summary> /// Initializes a new instance of <see cref="SkipTokenExpressionBuilder"/>. /// </summary> /// <param name="nodeToExpressionTranslator">The node to expression translator to use</param> internal SkipTokenExpressionBuilder(NodeToExpressionTranslator nodeToExpressionTranslator) { this.nodeToExpressionTranslator = nodeToExpressionTranslator; }
/// <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)); }
private void TestFunctionCall <TParam, TReturn>(string functionName, IEnumerable <SingleValueNode> parameters, Expression <Func <TParam, TReturn> > expectedExpression, NodeToExpressionTranslator translator = null) { if (translator == null) { translator = this.testSubject; } var node = new SingleValueFunctionCallNode(functionName, parameters, null); var result = translator.TranslateNode(node); CompareExpressions(expectedExpression.Body, result); }
public NodeToExpressionTranslatorTests() { this.functionExpressionBinder = new FunctionExpressionBinder(t => { throw new Exception(); }); this.customerResourceType = new ResourceType(typeof(Customer), ResourceTypeKind.EntityType, null, "Fake", "Customer", false) { IsOpenType = true }; var derivedCustomerResourceType = new ResourceType(typeof(DerivedCustomer), ResourceTypeKind.EntityType, this.customerResourceType, "Fake", "DerivedCustomer", false); this.weaklyBackedDerivedType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, derivedCustomerResourceType, "Fake", "WeaklyBackedCustomer", false) { CanReflectOnInstanceType = false }; var nameResourceProperty = new ResourceProperty("Name", ResourcePropertyKind.Key | ResourcePropertyKind.Primitive, ResourceType.GetPrimitiveResourceType(typeof(string))); this.customerResourceType.AddProperty(nameResourceProperty); var addressResourceType = new ResourceType(typeof(Address), ResourceTypeKind.ComplexType, null, "Fake", "Address", false); var addressResourceProperty = new ResourceProperty("Address", ResourcePropertyKind.ComplexType, addressResourceType); this.customerResourceType.AddProperty(addressResourceProperty); var namesResourceProperty = new ResourceProperty("Names", ResourcePropertyKind.Collection, ResourceType.GetCollectionResourceType(ResourceType.GetPrimitiveResourceType(typeof(string)))); this.customerResourceType.AddProperty(namesResourceProperty); var addressesResourceProperty = new ResourceProperty("Addresses", ResourcePropertyKind.Collection, ResourceType.GetCollectionResourceType(addressResourceType)); this.customerResourceType.AddProperty(addressesResourceProperty); var bestFriendResourceProperty = new ResourceProperty("BestFriend", ResourcePropertyKind.ResourceReference, this.customerResourceType); this.customerResourceType.AddProperty(bestFriendResourceProperty); var otherFriendsResourceProperty = new ResourceProperty("OtherFriends", ResourcePropertyKind.ResourceSetReference, this.customerResourceType); this.customerResourceType.AddProperty(otherFriendsResourceProperty); this.weaklyBackedResourceProperty = new ResourceProperty("WeaklyBacked", ResourcePropertyKind.Primitive, ResourceType.GetPrimitiveResourceType(typeof(string))) { CanReflectOnInstanceTypeProperty = false }; var guid1ResourceProperty = new ResourceProperty("Guid1", ResourcePropertyKind.Primitive, ResourceType.GetPrimitiveResourceType(typeof(Guid))); var guid2ResourceProperty = new ResourceProperty("Guid2", ResourcePropertyKind.Primitive, ResourceType.GetPrimitiveResourceType(typeof(Guid))); var nullableGuid1ResourceProperty = new ResourceProperty("NullableGuid1", ResourcePropertyKind.Primitive, ResourceType.GetPrimitiveResourceType(typeof(Guid?))); var nullableGuid2ResourceProperty = new ResourceProperty("NullableGuid2", ResourcePropertyKind.Primitive, ResourceType.GetPrimitiveResourceType(typeof(Guid?))); this.customerResourceType.AddProperty(guid1ResourceProperty); this.customerResourceType.AddProperty(guid2ResourceProperty); this.customerResourceType.AddProperty(nullableGuid1ResourceProperty); this.customerResourceType.AddProperty(nullableGuid2ResourceProperty); var resourceSet = new ResourceSet("Customers", this.customerResourceType); resourceSet.SetReadOnly(); var resourceSetWrapper = ResourceSetWrapper.CreateForTests(resourceSet, EntitySetRights.All); this.model = new EdmModel(); this.customerEdmType = new MetadataProviderEdmEntityType("Fake", this.customerResourceType, null, false, true, false, t => {}); this.model.AddElement(this.customerEdmType); this.derivedCustomerEdmType = new MetadataProviderEdmEntityType("Fake", derivedCustomerResourceType, this.customerEdmType, false, false, false, t => { }); this.model.AddElement(this.derivedCustomerEdmType); this.weaklyBackedCustomerEdmType = new MetadataProviderEdmEntityType("Fake", weaklyBackedDerivedType, this.derivedCustomerEdmType, false, false, false, t => { }); this.model.AddElement(this.weaklyBackedCustomerEdmType); this.nameProperty = new MetadataProviderEdmStructuralProperty(this.customerEdmType, nameResourceProperty, EdmCoreModel.Instance.GetString(true), null, EdmConcurrencyMode.None); this.customerEdmType.AddProperty(this.nameProperty); var addressEdmType = new MetadataProviderEdmComplexType("Fake", addressResourceType, null, false, false, t => {}); this.model.AddElement(addressEdmType); this.addressProperty = new MetadataProviderEdmStructuralProperty(this.customerEdmType, addressResourceProperty, new EdmComplexTypeReference(addressEdmType, true), null, EdmConcurrencyMode.None); this.customerEdmType.AddProperty(this.addressProperty); this.namesProperty = new MetadataProviderEdmStructuralProperty(this.customerEdmType, namesResourceProperty, new EdmCollectionTypeReference(new EdmCollectionType(EdmCoreModel.Instance.GetString(false))), null, EdmConcurrencyMode.None); this.customerEdmType.AddProperty(this.namesProperty); this.addressesProperty = new MetadataProviderEdmStructuralProperty(this.customerEdmType, addressesResourceProperty, new EdmCollectionTypeReference(new EdmCollectionType(new EdmComplexTypeReference(addressEdmType, false))), null, EdmConcurrencyMode.None); this.customerEdmType.AddProperty(this.addressesProperty); this.bestFriendNavigation = new MetadataProviderEdmNavigationProperty(this.customerEdmType, bestFriendResourceProperty, new EdmEntityTypeReference(this.customerEdmType, true)); this.customerEdmType.AddProperty(this.bestFriendNavigation); this.otherFriendsNavigation = new MetadataProviderEdmNavigationProperty(this.customerEdmType, otherFriendsResourceProperty, new EdmCollectionTypeReference(new EdmCollectionType(new EdmEntityTypeReference(this.customerEdmType, true)))); this.customerEdmType.AddProperty(this.otherFriendsNavigation); this.weaklyBackedProperty = new MetadataProviderEdmStructuralProperty(this.customerEdmType, this.weaklyBackedResourceProperty, EdmCoreModel.Instance.GetString(true), null, EdmConcurrencyMode.None); this.customerEdmType.AddProperty(this.weaklyBackedProperty); var guid1EdmProperty = new MetadataProviderEdmStructuralProperty(this.customerEdmType, guid1ResourceProperty, EdmCoreModel.Instance.GetGuid(false), null, EdmConcurrencyMode.None); this.customerEdmType.AddProperty(guid1EdmProperty); var guid2EdmProperty = new MetadataProviderEdmStructuralProperty(this.customerEdmType, guid2ResourceProperty, EdmCoreModel.Instance.GetGuid(false), null, EdmConcurrencyMode.None); this.customerEdmType.AddProperty(guid2EdmProperty); var nullableGuid1EdmProperty = new MetadataProviderEdmStructuralProperty(this.customerEdmType, nullableGuid1ResourceProperty, EdmCoreModel.Instance.GetGuid(true), null, EdmConcurrencyMode.None); this.customerEdmType.AddProperty(nullableGuid1EdmProperty); var nullableGuid2EdmProperty = new MetadataProviderEdmStructuralProperty(this.customerEdmType, nullableGuid2ResourceProperty, EdmCoreModel.Instance.GetGuid(true), null, EdmConcurrencyMode.None); this.customerEdmType.AddProperty(nullableGuid2EdmProperty); this.entitySet = new EdmEntitySetWithResourceSet(new EdmEntityContainer("Fake", "Container"), resourceSetWrapper, this.customerEdmType); ((EdmEntitySet)this.entitySet).AddNavigationTarget(this.bestFriendNavigation, this.entitySet); ((EdmEntitySet)this.entitySet).AddNavigationTarget(this.otherFriendsNavigation, this.entitySet); this.model.SetAnnotationValue(this.customerEdmType, this.customerResourceType); this.model.SetAnnotationValue(this.derivedCustomerEdmType, derivedCustomerResourceType); this.model.SetAnnotationValue(this.weaklyBackedCustomerEdmType, this.weaklyBackedDerivedType); this.model.SetAnnotationValue(this.nameProperty, nameResourceProperty); this.model.SetAnnotationValue(addressEdmType, addressResourceType); this.model.SetAnnotationValue(this.addressProperty, addressResourceProperty); this.model.SetAnnotationValue(this.namesProperty, namesResourceProperty); this.model.SetAnnotationValue(this.addressesProperty, addressesResourceProperty); this.model.SetAnnotationValue(this.bestFriendNavigation, bestFriendResourceProperty); this.model.SetAnnotationValue(this.otherFriendsNavigation, otherFriendsResourceProperty); this.model.SetAnnotationValue(this.weaklyBackedProperty, this.weaklyBackedResourceProperty); this.model.SetAnnotationValue(this.entitySet, resourceSetWrapper); this.model.SetAnnotationValue(guid1EdmProperty, guid1ResourceProperty); this.model.SetAnnotationValue(guid2EdmProperty, guid2ResourceProperty); this.model.SetAnnotationValue(nullableGuid1EdmProperty, nullableGuid1ResourceProperty); this.model.SetAnnotationValue(nullableGuid2EdmProperty, nullableGuid2ResourceProperty); this.testSubject = this.CreateTestSubject(); }
/// <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; }