public void Aggregation_NotSupportedException_ThrownForMemberAccessOnCollectionProperty(string aggregationMethodName) { // Arrange var queryable = this.dsContext.CreateQuery <Product>(productsEntitySetName); // Build selector expression, e.g. d1 => d1.CollectionProp.Member var parameterExpr = Expression.Parameter(queryable.ElementType, "d1"); var selectorExpr = Expression.Lambda( Expression.MakeMemberAccess( Expression.MakeMemberAccess(parameterExpr, typeof(Product).GetProperty("Sales")), typeof(Collection <Sale>).GetProperty("Count")), parameterExpr); var propertyType = ((MemberExpression)selectorExpr.Body).Type; // Get the aggregation method var aggregationMethod = GetAggregationMethod(aggregationMethodName, propertyType); var returnType = GetMethodReturnType(aggregationMethod, propertyType); // Build method call expression dynamically, e.g. Queryable.Average(d1 => d1.CollectionProp.Member) var methodCallExpr = BuildMethodCallExpression(queryable, aggregationMethod, selectorExpr); var queryProvider = new DataServiceQueryProvider(dsContext); // Get Execute method defined in DataServiceQueryProvider class var executeMethod = GetExecuteMethod(); // Act & Assert var ex = Assert.Throws <TargetInvocationException>(() => executeMethod.MakeGenericMethod(returnType).Invoke(queryProvider, new object[] { methodCallExpr })); Assert.True(ex.InnerException is NotSupportedException); }
public void Aggregation_ExpressionTranslatedToExpectedUri(string propertyName, string aggregationMethodName) { // Arrange var queryable = this.dsContext.CreateQuery <Number>(numbersEntitySetName); var propertyInfo = queryable.ElementType.GetProperty(propertyName); // Get the aggregation method var aggregationMethod = GetAggregationMethod(aggregationMethodName, propertyInfo.PropertyType); // Build method call expression dynamically, e.g. Queryable.Average(d1 => d1.Prop) var methodCallExpr = BuildMethodCallExpression(queryable, aggregationMethod, propertyInfo); // Act // Call factory method for creating DataServiceOrderedQuery based on expression var query = new DataServiceQueryProvider(dsContext).CreateQuery(methodCallExpr); // Assert // E.g. http://tempuri.org/Sales?apply=aggregate(Prop with average as AverageProp) var expectedAggregateUri = $"{serviceUri}/{numbersEntitySetName}?$apply=" + string.Format( aggregateTransformationTemplate, string.Format( aggregateExpressionTemplate, propertyName, aggregationMethodName.ToLower(), $"{aggregationMethodName}{propertyName}")); Assert.Equal(expectedAggregateUri, query.ToString()); }
public void CountDistinct_ExpressionTranslatedToExpectedUri() { // Arrange var queryable = this.dsContext.CreateQuery <Number>(numbersEntitySetName); var countDistinctMethod = GetCountDistinctMethod(); var propertyInfo = queryable.ElementType.GetProperty("RowParity"); var parameterExpr = Expression.Parameter(queryable.ElementType, "d1"); var selectorExpr = Expression.Lambda(Expression.MakeMemberAccess(parameterExpr, propertyInfo), parameterExpr); var methodCallExpr = Expression.Call( null, countDistinctMethod.MakeGenericMethod(new Type[] { queryable.ElementType, propertyInfo.PropertyType }), new[] { queryable.Expression, Expression.Quote(selectorExpr) }); // Act // Call factory method for creating DataServiceOrderedQuery based on expression var query = new DataServiceQueryProvider(dsContext).CreateQuery(methodCallExpr); // Assert var expectedAggregateUri = $"{serviceUri}/{numbersEntitySetName}?$apply=aggregate(RowParity with countdistinct as CountDistinctRowParity)"; Assert.Equal(expectedAggregateUri, query.ToString()); }
private TestQueryable <TElement> CreateSingletonQuery <TElement>(string singletonName) { SingletonResourceExpression exp = new SingletonResourceExpression(typeof(IOrderedQueryable <TElement>), null, Expression.Constant(singletonName), typeof(TElement), null, CountOption.None, null, null, null, null); DataServiceQueryProvider provider = new DataServiceQueryProvider(context); return(new TestQueryable <TElement>(exp, provider)); }
public void Aggregation_ReturnsExpectedResult(string propertyName, string aggregationMethodName) { // Arrange var queryable = this.dsContext.CreateQuery <Number>(numbersEntitySetName); var propertyInfo = queryable.ElementType.GetProperty(propertyName); // Get the aggregation method var aggregationMethod = GetAggregationMethod(aggregationMethodName, propertyInfo.PropertyType); var returnType = GetMethodReturnType(aggregationMethod, propertyInfo.PropertyType); // Build expression dynamically, e.g. [Queryable].Average(d1 => d1.Prop) var methodCallExpr = BuildMethodCallExpression(queryable, aggregationMethod, propertyInfo); // Mock aggregated response var aggregationAlias = $"{aggregationMethodName}{propertyName}"; // E.g. AverageProp var randomAggregateResult = GenerateRandomAggregateValue(aggregationMethodName, returnType); InterceptRequestAndMockResponse(aggregationAlias, randomAggregateResult); var queryProvider = new DataServiceQueryProvider(dsContext); // Get Execute method defined in DataServiceQueryProvider class var executeMethod = GetExecuteMethod(); // Act var result = executeMethod.MakeGenericMethod(returnType).Invoke(queryProvider, new object[] { methodCallExpr }); // Assert Assert.Equal(result, randomAggregateResult); }
/// <summary> /// Obtain the DataServiceContext from the incoming enumerable /// </summary> /// <param name="items">An IEnumerable that may be a DataServiceQuery or QueryOperationResponse object</param> /// <returns>DataServiceContext instance associated with the input</returns> private static DataServiceContext GetContextFromItems(IEnumerable <T> items) { Debug.Assert(items != null, "items != null"); DataServiceQuery <T> dataServiceQuery = items as DataServiceQuery <T>; if (dataServiceQuery != null) { DataServiceQueryProvider queryProvider = dataServiceQuery.Provider as DataServiceQueryProvider; Debug.Assert(queryProvider != null, "Got DataServiceQuery with unknown query provider."); DataServiceContext context = queryProvider.Context; Debug.Assert(context != null, "Query provider must always have valid context."); return(context); } QueryOperationResponse queryOperationResponse = items as QueryOperationResponse; if (queryOperationResponse != null) { Debug.Assert(queryOperationResponse.Results != null, "Got QueryOperationResponse without valid results."); DataServiceContext context = queryOperationResponse.Results.Context; Debug.Assert(context != null, "Materializer must always have valid context."); return(context); } throw new ArgumentException(Strings.DataServiceCollection_CannotDetermineContextFromItems); }
public void Aggregation_OnFilteredInputSet(string aggregationMethodName) { // Arrange var queryable = this.dsContext.CreateQuery <Sale>(salesEntitySetName); PropertyInfo propertyInfo = queryable.ElementType.GetProperty("Amount"); var parameter1Expr = Expression.Parameter(queryable.ElementType, "d1"); // d1.Amount var memberExpr = Expression.MakeMemberAccess(parameter1Expr, propertyInfo); // d1.Amount > 1 var greaterThanExpr = Expression.GreaterThan(memberExpr, Expression.Constant((decimal)1)); // Get Where method var whereMethod = GetWhereMethod(); // .Where(d1 => d1.Amount > 1) var whereExpr = Expression.Call( null, whereMethod.MakeGenericMethod(new Type[] { queryable.ElementType }), new[] { queryable.Expression, Expression.Lambda <Func <Sale, bool> >(greaterThanExpr, parameter1Expr) }); var parameter2Expr = Expression.Parameter(queryable.ElementType, "d2"); // d2 => d2.Amount var selectorExpr = Expression.Lambda( Expression.MakeMemberAccess(parameter2Expr, propertyInfo), parameter2Expr); var propertyType = ((MemberExpression)selectorExpr.Body).Type; // Get aggregation method var aggregationMethod = GetAggregationMethod(aggregationMethodName, propertyType); List <Type> genericArguments = new List <Type>(); genericArguments.Add(queryable.ElementType); if (aggregationMethod.GetGenericArguments().Length > 1) { genericArguments.Add(propertyType); } // E.g .Where(d1 => d1.Amount > 1).Average(d2 => d2.Amount) var aggregationMethodExpr = Expression.Call( null, aggregationMethod.MakeGenericMethod(genericArguments.ToArray()), new Expression[] { whereExpr, Expression.Quote(selectorExpr) }); // Act // Call factory method for creating DataServiceOrderedQuery based on expression var query = new DataServiceQueryProvider(dsContext).CreateQuery(aggregationMethodExpr); // Assert var expectedAggregateUri = $"{serviceUri}/{salesEntitySetName}?$apply=filter(Amount gt 1)" + $"/aggregate(Amount with {aggregationMethodName.ToLower()} as {aggregationMethodName}Amount)"; Assert.Equal(expectedAggregateUri, query.ToString()); }
/// <summary> /// query object of a function which returns a collection of items /// </summary> /// <param name="expression">expression for query</param> /// <param name="provider">query provider for query</param> /// <param name="isComposable">whether this query is composable</param> public DataServiceQuery(Expression expression, DataServiceQueryProvider provider, bool isComposable) { Debug.Assert(provider.Context != null, "null context"); Debug.Assert(expression != null, "null expression"); Debug.Assert(provider is DataServiceQueryProvider, "Currently only support Web Query Provider"); this.queryExpression = expression; this.queryProvider = provider; this.IsComposable = isComposable; this.IsFunction = true; }
public void TranslatesEnumerableContainsWithOtherClauses() { // Arrange var sut = new DataServiceQueryProvider(dsc); var products = dsc.CreateQuery <Product>("Products") .Where(product => new[] { "Milk", "Flour" }.Contains(product.Name) && product.Price < 5); // Act var queryComponents = sut.Translate(products.Expression); // Assert Assert.Equal(@"http://root/Products?$filter=Name in ('Milk','Flour') and Price lt 5", queryComponents.Uri.ToString()); }
public void TranslatesEnumerableContainsWithSingleItem() { // Arrange var sut = new DataServiceQueryProvider(dsc); var products = dsc.CreateQuery <Product>("Products") .Where(product => new[] { "Pancake mix" }.Contains(product.Name)); // Act var queryComponents = sut.Translate(products.Expression); // Assert Assert.Equal(@"http://root/Products?$filter=Name in ('Pancake mix')", queryComponents.Uri.ToString()); }
public void ThrowsForEnumerableContainsWithEmptyCollection() { // Arrange var sut = new DataServiceQueryProvider(dsc); var products = dsc.CreateQuery <Product>("Products") .Where(product => Enumerable.Empty <string>().Contains(product.Name)); // Act var exception = Assert.ThrowsAny <InvalidOperationException>(() => sut.Translate(products.Expression)); // Assert Assert.Equal(Strings.ALinq_ContainsNotValidOnEmptyCollection, exception.Message); }
public void EnumerableContainsOnCollectionValuedPropertiesWithMemberAccessIsNotSupported() { // Arrange var sut = new DataServiceQueryProvider(dsc); var products = dsc.CreateQuery <Product>("Products") .Where(product => product.Comments.Contains(product.Name)); // Act var exception = Assert.ThrowsAny <NotSupportedException>(() => sut.Translate(products.Expression)); // Assert Assert.Equal("The method 'Contains' is not supported.", exception.Message); }
public void TranslatesEnumerableContainsToInOperator() { // Arrange var sut = new DataServiceQueryProvider(dsc); var productNames = new[] { "Milk", "Cheese", "Donut" }; var products = dsc.CreateQuery <Product>("Products") .Where(product => productNames.Contains(product.Name)); // Act var queryComponents = sut.Translate(products.Expression); // Assert Assert.Equal(@"http://root/Products?$filter=Name in ('Milk','Cheese','Donut')", queryComponents.Uri.ToString()); }
public void TranslatesStringContainsToContainsFunction() { // Arrange var sut = new DataServiceQueryProvider(dsc); var search = "Strawberry"; var products = dsc.CreateQuery <Product>("Products") .Where(product => product.Name.Contains(search)); // Act var queryComponents = sut.Translate(products.Expression); // Assert Assert.Equal(@"http://root/Products?$filter=contains(Name,'Strawberry')", queryComponents.Uri.ToString()); }
public void Aggregation_TargetingNavProperty_ReturnsExpectedResult(string aggregationMethodName) { // Arrange var queryable = this.dsContext.CreateQuery <Sale>(salesEntitySetName); var navPropertyName = "Product"; var propertyName = "TaxRate"; // Build selector expression, e.g. d1 => d1.NavProp.Prop var parameterExpr = Expression.Parameter(queryable.ElementType, "d1"); var selectorExpr = Expression.Lambda( Expression.MakeMemberAccess( Expression.MakeMemberAccess(parameterExpr, typeof(Sale).GetProperty(navPropertyName)), typeof(Product).GetProperty(propertyName)), parameterExpr); var propertyType = ((MemberExpression)selectorExpr.Body).Type; // Get the aggregation method var aggregationMethod = GetAggregationMethod(aggregationMethodName, propertyType); var returnType = GetMethodReturnType(aggregationMethod, propertyType); // Build expression dynamically, e.g. [Queryable].Average(d1 => d1.NavProp.Prop) var methodCallExpr = BuildMethodCallExpression(queryable, aggregationMethod, selectorExpr); // Mock aggregated response var aggregationAlias = $"{aggregationMethodName}{navPropertyName}_{propertyName}"; // E.g. AverageNavProp_Prop var randomAggregateResult = GenerateRandomAggregateValue(aggregationMethodName, returnType); InterceptRequestAndMockResponse(aggregationAlias, randomAggregateResult); var queryProvider = new DataServiceQueryProvider(dsContext); // Get Execute method defined in DataServiceQueryProvider class var executeMethod = GetExecuteMethod(); // Act var result = executeMethod.MakeGenericMethod(returnType).Invoke(queryProvider, new object[] { methodCallExpr }); // Assert Assert.Equal(result, randomAggregateResult); }
public void Aggregation_TargetingNavProperty_ExpressionTranslatedToExpectedUri(string aggregationMethodName) { var queryable = this.dsContext.CreateQuery <Sale>(salesEntitySetName); var navPropertyName = "Product"; var propertyName = "TaxRate"; // Build selector expression, e.g. d1 => d1.NavProp.Prop var parameterExpr = Expression.Parameter(queryable.ElementType, "d1"); var selectorExpr = Expression.Lambda( Expression.MakeMemberAccess( Expression.MakeMemberAccess(parameterExpr, typeof(Sale).GetProperty(navPropertyName)), typeof(Product).GetProperty(propertyName)), parameterExpr); var propertyType = ((MemberExpression)selectorExpr.Body).Type; // Get the aggregation method var aggregationMethod = GetAggregationMethod(aggregationMethodName, propertyType); // Build expression dynamically, e.g. [Queryable].Average(d1 => d1.NavProp.Prop) var methodCallExpr = BuildMethodCallExpression(queryable, aggregationMethod, selectorExpr); // Act // Call factory method for creating DataServiceOrderedQuery based on expression var query = new DataServiceQueryProvider(dsContext).CreateQuery(methodCallExpr); // Assert // E.g. http://tempuri.org/Sales?apply=aggregate(NavProp/Prop with average as AverageNavProp_Prop) var expectedAggregateUri = $"{serviceUri}/{salesEntitySetName}?$apply=" + string.Format( aggregateTransformationTemplate, string.Format( aggregateExpressionTemplate, $"{navPropertyName}/{propertyName}", aggregationMethodName.ToLower(), $"{aggregationMethodName}{navPropertyName}_{propertyName}")); Assert.Equal(expectedAggregateUri, query.ToString()); }
/// <summary> /// query object /// </summary> /// <param name="expression">expression for query</param> /// <param name="provider">query provider for query</param> public DataServiceQuery(Expression expression, DataServiceQueryProvider provider) : this(expression, provider, true) { this.IsFunction = false; }
/// <summary> /// constructor /// </summary> /// <param name="expression">expression for query</param> /// <param name="provider">query provider for query</param> /// <param name="isComposable">whether this query is composable</param> internal DataServiceOrderedQuery(Expression expression, DataServiceQueryProvider provider, bool isComposable) : base(expression, provider, isComposable) { }
/// <summary> /// constructor /// </summary> /// <param name="expression">expression for query</param> /// <param name="provider">query provider for query</param> internal DataServiceOrderedQuery(Expression expression, DataServiceQueryProvider provider) : base(expression, provider) { }
public DSMethodTranslatingVisitor(DataServiceQueryProvider.ResultSetCollection resultSets) { this.resultSets = resultSets; }
internal TestQueryable(Expression ex, DataServiceQueryProvider provider) { this.Expression = ex; this.queryProvider = provider; }