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());
        }
Exemple #4
0
        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);
        }
Exemple #6
0
        /// <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;
		}
Exemple #21
0
 internal TestQueryable(Expression ex, DataServiceQueryProvider provider)
 {
     this.Expression    = ex;
     this.queryProvider = provider;
 }