public void BindApplyWithAggregateShouldReturnApplyClause() { IEnumerable <QueryToken> tokens = _parser.ParseApply("aggregate(UnitPrice with sum as TotalPrice)"); ApplyBinder binder = new ApplyBinder(FakeBindMethods.BindSingleComplexProperty, _bindingState); ApplyClause actual = binder.BindApply(tokens); actual.Should().NotBeNull(); actual.Transformations.Should().HaveCount(1); List <TransformationNode> transformations = actual.Transformations.ToList(); AggregateTransformationNode aggregate = transformations[0] as AggregateTransformationNode; aggregate.Should().NotBeNull(); aggregate.Kind.Should().Be(TransformationNodeKind.Aggregate); aggregate.AggregateExpressions.Should().NotBeNull(); aggregate.AggregateExpressions.Should().HaveCount(1); List <AggregateExpressionBase> statements = aggregate.AggregateExpressions.ToList(); AggregateExpression statement = statements[0] as AggregateExpression; statement.Should().NotBeNull(); VerifyIsFakeSingleValueNode(statement.Expression); statement.Method.Should().Be(AggregationMethod.Sum); statement.Alias.Should().Be("TotalPrice"); }
private MethodCallExpression ApplyAggregate(Expression source, AggregateTransformationNode transformation) { Type sourceType = OeExpressionHelper.GetCollectionItemType(source.Type); ParameterExpression sourceParameter = Expression.Parameter(sourceType); ParameterExpression lambdaParameter = sourceParameter; var expressions = new List <Expression>(); if (sourceType.GetGenericTypeDefinition() == typeof(IGrouping <,>)) { PropertyInfo keyProperty = sourceType.GetTypeInfo().GetProperty(nameof(IGrouping <Object, Object> .Key)); MemberExpression key = Expression.Property(sourceParameter, keyProperty); expressions.Add(key); lambdaParameter = Expression.Parameter(sourceType.GetTypeInfo().GetGenericArguments()[1]); } var visitor = CreateVisitor(lambdaParameter); foreach (AggregateExpression aggExpression in transformation.Expressions) { Expression e = visitor.TranslateNode(aggExpression.Expression); LambdaExpression aggLambda = Expression.Lambda(e, lambdaParameter); MethodCallExpression aggCallExpression = AggCallExpression(aggExpression.Method, sourceParameter, aggLambda); expressions.Add(aggCallExpression); _aggProperties.Add(CreateEdmProperty(_visitor.EdmModel, aggCallExpression.Type, aggExpression.Alias, false)); } NewExpression newExpression = OeExpressionHelper.CreateTupleExpression(expressions); MethodInfo selectMethodInfo = OeMethodInfoHelper.GetSelectMethodInfo(sourceType, newExpression.Type); LambdaExpression lambda = Expression.Lambda(newExpression, sourceParameter); return(Expression.Call(selectMethodInfo, source, lambda)); }
public void BindApplyWithEntitySetAggregationReturnApplyClause() { IEnumerable <QueryToken> tokens = _parser.ParseApply( "groupby((LifeTime),aggregate(MyPaintings($count as Count)))"); BindingState state = new BindingState(_configuration); MetadataBinder metadataBiner = new MetadataBinder(_bindingState); ApplyBinder binder = new ApplyBinder(metadataBiner.Bind, _bindingState); ApplyClause actual = binder.BindApply(tokens); actual.Should().NotBeNull(); actual.Transformations.Should().HaveCount(1); GroupByTransformationNode groupBy = actual.Transformations.First() as GroupByTransformationNode; groupBy.Should().NotBeNull(); groupBy.GroupingProperties.Should().HaveCount(1); AggregateTransformationNode aggregate = groupBy.ChildTransformations as AggregateTransformationNode; aggregate.Should().NotBeNull(); aggregate.AggregateExpressions.Should().HaveCount(1); EntitySetAggregateExpression entitySetAggregate = aggregate.AggregateExpressions.First() as EntitySetAggregateExpression; entitySetAggregate.Should().NotBeNull(); }
public void BindApplyWithExpandReturnApplyClause() { IEnumerable <QueryToken> tokens = _parser.ParseApply( "expand(MyPaintings, filter(FrameColor eq 'Red'))/groupby((LifeTime),aggregate(MyPaintings($count as Count)))"); BindingState state = new BindingState(_configuration); MetadataBinder metadataBiner = new MetadataBinder(_bindingState); ApplyBinder binder = new ApplyBinder(metadataBiner.Bind, _bindingState, V4configuration, new ODataPathInfo(HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet())); ApplyClause actual = binder.BindApply(tokens); Assert.NotNull(actual); Assert.Equal(2, actual.Transformations.Count()); ExpandTransformationNode expand = Assert.IsType <ExpandTransformationNode>(actual.Transformations.First()); Assert.NotNull(expand.ExpandClause); ExpandedNavigationSelectItem expandItem = Assert.IsType <ExpandedNavigationSelectItem>(Assert.Single(expand.ExpandClause.SelectedItems)); Assert.Equal("Paintings", expandItem.NavigationSource.Name); Assert.NotNull(expandItem.FilterOption); GroupByTransformationNode groupBy = Assert.IsType <GroupByTransformationNode>(actual.Transformations.Last()); Assert.Single(groupBy.GroupingProperties); AggregateTransformationNode aggregate = Assert.IsType <AggregateTransformationNode>(groupBy.ChildTransformations); Assert.IsType <EntitySetAggregateExpression>(Assert.Single(aggregate.AggregateExpressions)); }
public void BindApplyWitMultipleTokensShouldReturnApplyClause() { IEnumerable <QueryToken> tokens = _parser.ParseApply( "groupby((ID, SSN, LifeTime))/aggregate(LifeTime with sum as TotalLife)/groupby((TotalLife))/aggregate(TotalLife with sum as TotalTotalLife)"); BindingState state = new BindingState(_configuration); MetadataBinder metadataBiner = new MetadataBinder(_bindingState); ApplyBinder binder = new ApplyBinder(metadataBiner.Bind, _bindingState); ApplyClause actual = binder.BindApply(tokens); actual.Should().NotBeNull(); actual.Transformations.Should().HaveCount(4); List <TransformationNode> transformations = actual.Transformations.ToList(); GroupByTransformationNode firstGroupBy = transformations[0] as GroupByTransformationNode; firstGroupBy.Should().NotBeNull(); TransformationNode firstAggregate = transformations[1] as AggregateTransformationNode; firstAggregate.Should().NotBeNull(); TransformationNode scecondGroupBy = transformations[2] as GroupByTransformationNode; scecondGroupBy.Should().NotBeNull(); AggregateTransformationNode scecondAggregate = transformations[3] as AggregateTransformationNode; scecondAggregate.Should().NotBeNull(); }
private MethodCallExpression ApplyAggregate(Expression source, AggregateTransformationNode transformation) { Type sourceType = OeExpressionHelper.GetCollectionItemType(source.Type); ParameterExpression sourceParameter = Expression.Parameter(sourceType); ParameterExpression lambdaParameter = sourceParameter; var expressions = new List <Expression>(); bool isGroupBy = sourceType.GetGenericTypeDefinition() == typeof(IGrouping <,>); if (isGroupBy) { PropertyInfo keyProperty = sourceType.GetProperty(nameof(IGrouping <Object, Object> .Key)) !; MemberExpression key = Expression.Property(sourceParameter, keyProperty); expressions.Add(key); lambdaParameter = Expression.Parameter(sourceType.GetGenericArguments()[1]); } var visitor = CreateVisitor(lambdaParameter); foreach (AggregateExpressionBase aggExpressionBase in transformation.AggregateExpressions) { if (aggExpressionBase is AggregateExpression aggExpression) { MethodCallExpression aggCallExpression; if (aggExpression.Method == AggregationMethod.VirtualPropertyCount) { aggCallExpression = CountExpression(sourceParameter); } else { Expression expression = visitor.TranslateNode(aggExpression.Expression); if (isGroupBy && expression is MemberExpression propertyExpression) { MemberExpression?keyPropertyExpression = FindInGroupByKey(source, expressions[0], propertyExpression); if (keyPropertyExpression != null) { expression = keyPropertyExpression; } } LambdaExpression aggLambda = Expression.Lambda(expression, lambdaParameter); aggCallExpression = AggCallExpression(aggExpression.Method, sourceParameter, aggLambda); } expressions.Add(aggCallExpression); _aggProperties.Add(CreateEdmProperty(aggCallExpression.Type, aggExpression.Alias, false)); } else { throw new NotSupportedException("Unknown aggregate expression type " + aggExpressionBase.GetType().Name); } } NewExpression newExpression = OeExpressionHelper.CreateTupleExpression(expressions); MethodInfo selectMethodInfo = OeMethodInfoHelper.GetSelectMethodInfo(sourceType, newExpression.Type); LambdaExpression lambda = Expression.Lambda(newExpression, sourceParameter); return(Expression.Call(selectMethodInfo, source, lambda)); }
private bool CompareAggregate(AggregateTransformationNode node1, AggregateTransformationNode node2) { if (node1 == node2) { return(true); } if (node1 == null || node2 == null) { return(false); } return(EnumerableComparer.Compare(node1.Expressions, node2.Expressions, CompareAggregate)); }
public void BindApplyWithCountInAggregateShouldReturnApplyClause() { IEnumerable <QueryToken> tokens = _parser.ParseApply("aggregate($count as TotalCount)"); ApplyBinder binder = new ApplyBinder(FakeBindMethods.BindSingleComplexProperty, _bindingState); ApplyClause actual = binder.BindApply(tokens); Assert.NotNull(actual); AggregateTransformationNode aggregate = Assert.IsType <AggregateTransformationNode>(Assert.Single(actual.Transformations)); Assert.Equal(TransformationNodeKind.Aggregate, aggregate.Kind); Assert.NotNull(aggregate.Expressions); AggregateExpression statement = Assert.Single(aggregate.Expressions); Assert.Equal(AggregationMethod.VirtualPropertyCount, statement.Method); Assert.Equal("TotalCount", statement.Alias); }
public void BindApplyWithEntitySetAggregationWithoutGroupByReturnApplyClause() { IEnumerable <QueryToken> tokens = _parser.ParseApply( "aggregate(MyPaintings(Value with sum as TotalValue))"); BindingState state = new BindingState(_configuration); MetadataBinder metadataBiner = new MetadataBinder(_bindingState); ApplyBinder binder = new ApplyBinder(metadataBiner.Bind, _bindingState); ApplyClause actual = binder.BindApply(tokens); Assert.NotNull(actual); Assert.NotNull(actual.Transformations); AggregateTransformationNode aggregate = Assert.IsType <AggregateTransformationNode>(Assert.Single(actual.Transformations)); Assert.NotNull(aggregate.AggregateExpressions); Assert.IsType <EntitySetAggregateExpression>(Assert.Single(aggregate.AggregateExpressions)); }
public void BindApplyWithAggregateShouldReturnApplyClause() { IEnumerable <QueryToken> tokens = _parser.ParseApply("aggregate(UnitPrice with sum as TotalPrice)"); ApplyBinder binder = new ApplyBinder(FakeBindMethods.BindSingleComplexProperty, _bindingState); ApplyClause actual = binder.BindApply(tokens); Assert.NotNull(actual); AggregateTransformationNode aggregate = Assert.IsType <AggregateTransformationNode>(Assert.Single(actual.Transformations)); Assert.Equal(TransformationNodeKind.Aggregate, aggregate.Kind); Assert.NotNull(aggregate.AggregateExpressions); AggregateExpression statement = Assert.IsType <AggregateExpression>(Assert.Single(aggregate.AggregateExpressions)); VerifyIsFakeSingleValueNode(statement.Expression); Assert.Equal(AggregationMethod.Sum, statement.Method); Assert.Equal("TotalPrice", statement.Alias); }
private void Translate(AggregateTransformationNode transformation) { bool appendComma = false; foreach (AggregateExpression aggExpression in transformation.Expressions) { appendComma = AppendComma(appendComma); if (aggExpression.Method != AggregationMethod.VirtualPropertyCount) { AppendExpression(aggExpression.Expression); query.Append(ExpressionConstants.SymbolEscapedSpace); AppendWord(ExpressionConstants.KeywordWith); } AppendWord(GetAggregationMethodName(aggExpression)); AppendWord(ExpressionConstants.KeywordAs); query.Append(aggExpression.Alias); } }
public void BindVirtualPropertiesAfterCollapseReturnsApplyClause() { IEnumerable <QueryToken> tokens = _parser.ParseApply( "groupby((ID))/aggregate($count as Count)"); BindingState state = new BindingState(_configuration); MetadataBinder metadataBiner = new MetadataBinder(_bindingState); ApplyBinder binder = new ApplyBinder(metadataBiner.Bind, _bindingState); ApplyClause actual = binder.BindApply(tokens); Assert.NotNull(actual); Assert.Equal(2, actual.Transformations.Count()); Assert.IsType <GroupByTransformationNode>(actual.Transformations.First()); AggregateTransformationNode aggregate = Assert.IsType <AggregateTransformationNode>(actual.Transformations.Last()); AggregateExpression aggExp = Assert.IsType <AggregateExpression>(Assert.Single(aggregate.AggregateExpressions)); Assert.Equal(AggregationMethod.VirtualPropertyCount, aggExp.Method); }
public void BindApplyWithAverageInAggregateShouldReturnApplyClause() { IEnumerable <QueryToken> tokens = _parser.ParseApply("aggregate(UnitPrice with average as AveragePrice)"); ApplyBinder binder = new ApplyBinder(FakeBindMethods.BindMethodReturningASingleFloatPrimitive, _bindingState); ApplyClause actual = binder.BindApply(tokens); Assert.NotNull(actual); AggregateTransformationNode aggregate = Assert.IsType <AggregateTransformationNode>(Assert.Single(actual.Transformations)); Assert.Equal(TransformationNodeKind.Aggregate, aggregate.Kind); Assert.NotNull(aggregate.AggregateExpressions); AggregateExpression statement = Assert.IsType <AggregateExpression>(Assert.Single(aggregate.AggregateExpressions)); Assert.NotNull(statement.Expression); Assert.Same(FakeBindMethods.FakeSingleFloatPrimitive, statement.Expression); Assert.Equal(AggregationMethod.Average, statement.Method); Assert.Equal("AveragePrice", statement.Alias); }
public void BindApplyWithExpandReturnApplyClause() { IEnumerable <QueryToken> tokens = _parser.ParseApply( "expand(MyPaintings, filter(FrameColor eq 'Red'))/groupby((LifeTime),aggregate(MyPaintings($count as Count)))"); BindingState state = new BindingState(_configuration); MetadataBinder metadataBiner = new MetadataBinder(_bindingState); ApplyBinder binder = new ApplyBinder(metadataBiner.Bind, _bindingState, V4configuration, new ODataPathInfo(HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet())); ApplyClause actual = binder.BindApply(tokens); actual.Should().NotBeNull(); actual.Transformations.Should().HaveCount(2); ExpandTransformationNode expand = actual.Transformations.First() as ExpandTransformationNode; expand.Should().NotBeNull(); expand.ExpandClause.Should().NotBeNull(); expand.ExpandClause.SelectedItems.Should().HaveCount(1); ExpandedNavigationSelectItem expandItem = expand.ExpandClause.SelectedItems.First() as ExpandedNavigationSelectItem; expandItem.Should().NotBeNull(); expandItem.NavigationSource.Name.ShouldBeEquivalentTo("Paintings"); expandItem.FilterOption.Should().NotBeNull(); GroupByTransformationNode groupBy = actual.Transformations.Last() as GroupByTransformationNode; groupBy.Should().NotBeNull(); groupBy.GroupingProperties.Should().HaveCount(1); AggregateTransformationNode aggregate = groupBy.ChildTransformations as AggregateTransformationNode; aggregate.Should().NotBeNull(); aggregate.AggregateExpressions.Should().HaveCount(1); EntitySetAggregateExpression entitySetAggregate = aggregate.AggregateExpressions.First() as EntitySetAggregateExpression; entitySetAggregate.Should().NotBeNull(); }
public void BindVirtualPropertiesAfterCollapseReturnsApplyClause() { IEnumerable <QueryToken> tokens = _parser.ParseApply( "groupby((ID))/aggregate($count as Count)"); BindingState state = new BindingState(_configuration); MetadataBinder metadataBiner = new MetadataBinder(_bindingState); ApplyBinder binder = new ApplyBinder(metadataBiner.Bind, _bindingState); ApplyClause actual = binder.BindApply(tokens); actual.Should().NotBeNull(); actual.Transformations.Should().HaveCount(2); GroupByTransformationNode groupby = actual.Transformations.First() as GroupByTransformationNode; groupby.Should().NotBeNull(); AggregateTransformationNode aggregate = actual.Transformations.Last() as AggregateTransformationNode; aggregate.Should().NotBeNull(); aggregate.AggregateExpressions.Should().HaveCount(1); aggregate.AggregateExpressions.Single().As <AggregateExpression>().Method.ShouldBeEquivalentTo(AggregationMethod.VirtualPropertyCount); }
public void BindApplyWithEntitySetAggregationWithoutGroupByReturnApplyClause() { IEnumerable <QueryToken> tokens = _parser.ParseApply( "aggregate(MyPaintings(Value with sum as TotalValue))"); BindingState state = new BindingState(_configuration); MetadataBinder metadataBiner = new MetadataBinder(_bindingState); ApplyBinder binder = new ApplyBinder(metadataBiner.Bind, _bindingState); ApplyClause actual = binder.BindApply(tokens); actual.Should().NotBeNull(); actual.Transformations.Should().HaveCount(1); AggregateTransformationNode aggregate = actual.Transformations.First() as AggregateTransformationNode; aggregate.Should().NotBeNull(); aggregate.AggregateExpressions.Should().HaveCount(1); EntitySetAggregateExpression entitySetAggregate = aggregate.AggregateExpressions.First() as EntitySetAggregateExpression; entitySetAggregate.Should().NotBeNull(); }
public void BindApplyWithEntitySetAggregationReturnApplyClause() { IEnumerable <QueryToken> tokens = _parser.ParseApply( "groupby((LifeTime),aggregate(MyPaintings($count as Count)))"); BindingState state = new BindingState(_configuration); MetadataBinder metadataBiner = new MetadataBinder(_bindingState); ApplyBinder binder = new ApplyBinder(metadataBiner.Bind, _bindingState); ApplyClause actual = binder.BindApply(tokens); Assert.NotNull(actual); Assert.NotNull(actual.Transformations); GroupByTransformationNode groupBy = Assert.IsType <GroupByTransformationNode>(Assert.Single(actual.Transformations)); Assert.NotNull(groupBy.GroupingProperties); AggregateTransformationNode aggregate = Assert.IsType <AggregateTransformationNode>(groupBy.ChildTransformations); Assert.NotNull(aggregate.AggregateExpressions); Assert.IsType <EntitySetAggregateExpression>(Assert.Single(aggregate.AggregateExpressions)); }
public void BindApplyWithCountInAggregateShouldReturnApplyClause() { IEnumerable <QueryToken> tokens = _parser.ParseApply("aggregate($count as TotalCount)"); ApplyBinder binder = new ApplyBinder(FakeBindMethods.BindSingleComplexProperty, _bindingState); ApplyClause actual = binder.BindApply(tokens); actual.Should().NotBeNull(); actual.Transformations.Should().HaveCount(1); List <TransformationNode> transformations = actual.Transformations.ToList(); AggregateTransformationNode aggregate = transformations[0] as AggregateTransformationNode; aggregate.Should().NotBeNull(); aggregate.Kind.Should().Be(TransformationNodeKind.Aggregate); aggregate.Expressions.Should().NotBeNull(); aggregate.Expressions.Should().HaveCount(1); List <AggregateExpression> statements = aggregate.Expressions.ToList(); AggregateExpression statement = statements[0]; statement.Method.Should().Be(AggregationMethod.VirtualPropertyCount); statement.Alias.Should().Be("TotalCount"); }
private void AddAggregationPropertiesToModel(AggregateTransformationNode aggregationProperties , EdmEntityTypeSettings sourceEdmSetting , EdmEntityType edmEntityType , Dictionary <string, AggregateExpression> aggregatePropList , EdmEntityTypeSettings targetEdmSetting , EdmComplexType edmComplexType , Dictionary <string, object> latestStateDictionary) { foreach (var aggregationExpression in aggregationProperties.AggregateExpressions) { var expr = (AggregateExpression)aggregationExpression; if (expr.Method != AggregationMethod.Custom) { bool? isNullable = null; string propertyAlias = ""; var primitiveKind = expr.Expression.TypeReference.PrimitiveKind(); if (expr.Method == AggregationMethod.VirtualPropertyCount) { var sourceProperty = (CountVirtualPropertyNode)expr.Expression; isNullable = sourceProperty.TypeReference.IsNullable; propertyAlias = !string.IsNullOrWhiteSpace(expr.Alias) ? expr.Alias : sourceProperty.Kind.ToString(); primitiveKind = EdmPrimitiveTypeKind.Int32; } else { var sourceProperty = (SingleValuePropertyAccessNode)expr.Expression; var sourceEdmProperty = sourceEdmSetting.Properties.FirstOrDefault(predicate => predicate.PropertyName.Equals(sourceProperty.Property.Name)); isNullable = sourceEdmProperty.IsNullable; propertyAlias = !string.IsNullOrWhiteSpace(expr.Alias) ? expr.Alias : sourceProperty.Property.Name; if (expr.Method == AggregationMethod.Average) { primitiveKind = EdmPrimitiveTypeKind.Double; } if (expr.Method == AggregationMethod.CountDistinct) { primitiveKind = EdmPrimitiveTypeKind.Int32; } } edmEntityType.AddStructuralProperty(propertyAlias, primitiveKind); aggregatePropList.Add(propertyAlias, expr); targetEdmSetting.Properties.Add(new EdmEntityTypePropertySetting { PropertyName = propertyAlias, PropertyType = GetStringTypeFromEdmPrimitiveType(primitiveKind), IsNullable = isNullable }); } else { //Create a list of source type if (expr.MethodDefinition.MethodLabel.Contains(ODataFilterConstants.AggregationMethod_Custom_List, StringComparison.OrdinalIgnoreCase)) { foreach (var property in sourceEdmSetting.Properties) { edmComplexType.AddStructuralProperty(property.PropertyName, property.GetEdmPrimitiveTypeKind()); } var groupItemsPropertyName = !string.IsNullOrWhiteSpace(expr.Alias) ? expr.Alias : "Items"; var complexTypeReference = new EdmComplexTypeReference(edmComplexType, true); edmEntityType.AddStructuralProperty(groupItemsPropertyName, new EdmCollectionTypeReference(new EdmCollectionType(complexTypeReference))); aggregatePropList.Add(groupItemsPropertyName, expr); targetEdmSetting.Properties.Add(new EdmEntityTypePropertySetting { PropertyName = groupItemsPropertyName, PropertyType = "List", IsNullable = null }); latestStateDictionary.Add(RequestFilterConstants.GetComplexTypeKeyName(ApplyParser, StepIndex), edmComplexType); } else if (expr.MethodDefinition.MethodLabel.Contains(ODataFilterConstants.AggregationMethod_Custom_CountDistinct, StringComparison.OrdinalIgnoreCase) || expr.MethodDefinition.MethodLabel.Contains(ODataFilterConstants.AggregationMethod_Custom_Count, StringComparison.OrdinalIgnoreCase)) { var sourceProperty = (SingleValuePropertyAccessNode)expr.Expression; var primitiveKind = EdmPrimitiveTypeKind.Int32; var countDistinctPropName = !string.IsNullOrWhiteSpace(expr.Alias) ? expr.Alias : sourceProperty.Property.Name; edmEntityType.AddStructuralProperty(countDistinctPropName, primitiveKind); aggregatePropList.Add(countDistinctPropName, expr); targetEdmSetting.Properties.Add(new EdmEntityTypePropertySetting { PropertyName = countDistinctPropName, PropertyType = GetStringTypeFromEdmPrimitiveType(primitiveKind), IsNullable = null }); } else { throw new FeatureNotSupportedException($"{ApplyParser}-Custom Aggregation-{expr.MethodDefinition.MethodLabel}", "Invalid Custom Aggregation"); } } } }
private void Translate(AggregateTransformationNode transformation) { Translate(transformation.AggregateExpressions); }