protected override Expression VisitAggregate(AggregateExpression aggregate) { // COUNT(*) forces all columns to be retained in subquery if (aggregate.AggregateName == "Count" && aggregate.Argument == null) { this.retainAllColumns = true; } return base.VisitAggregate(aggregate); }
protected AggregateExpression UpdateAggregate(AggregateExpression aggregate, Type type, string aggType, Expression arg, bool isDistinct) { if (type != aggregate.Type || aggType != aggregate.AggregateName || arg != aggregate.Argument || isDistinct != aggregate.IsDistinct) { return new AggregateExpression(type, aggType, arg, isDistinct); } return aggregate; }
protected virtual Expression VisitAggregate(AggregateExpression aggregate) { Expression arg = this.Visit(aggregate.Argument); if (arg != aggregate.Argument) { return new AggregateExpression(aggregate.Type, aggregate.AggregateType, arg, aggregate.IsDistinct); } return aggregate; }
protected internal virtual Expression VisitAggregate(AggregateExpression aggregate) { var expressions = Visit(aggregate.Arguments); if (expressions != aggregate.Arguments) { return(new AggregateExpression(aggregate.Type, aggregate.AggregateFunction, expressions)); } return(aggregate); }
private void AverageAggregate(AggregateExpression aggregate) { var old = _currentAggregateName; _currentAggregateName = old + "Cnt"; CountAggregate(aggregate); _currentAggregateName = old + "Sum"; SumAggregate(aggregate); _currentAggregateName = old; }
private AggregateExpression FixCustomMethodReturnType(AggregateExpression expression) { if (expression.Method != AggregationMethod.Custom) { return expression; } var customMethod = GetCustomMethod(expression); var typeReference = EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(customMethod.ReturnType); return new AggregateExpression(expression.Expression, expression.MethodDefinition, expression.Alias, typeReference); }
private AggregateExpression FixCustomMethodReturnType(AggregateExpression expression) { if (expression.Method != AggregationMethod.Custom) { return(expression); } var customMethod = GetCustomMethod(expression); var typeReference = customMethod.ReturnType.GetEdmPrimitiveTypeReference(); return(new AggregateExpression(expression.Expression, expression.MethodDefinition, expression.Alias, typeReference)); }
protected override Expression VisitAggregate(AggregateExpression aggregate) { var saveInAggregate = this.inAggregate; this.inAggregate = true; var result = base.VisitAggregate(aggregate); this.inAggregate = saveInAggregate; return result; }
protected internal override Expression VisitAggregate(AggregateExpression aggregate) { var saveInAggregate = this.inAggregate; this.inAggregate = true; var result = base.VisitAggregate(aggregate); this.inAggregate = saveInAggregate; return(result); }
protected override Expression VisitAggregate(AggregateExpression aggregate) { if (aggregate.AggregateType == AggregateType.Average) { Write("TRUNC("); var exp = base.VisitAggregate(aggregate); Write(", 20)"); return(exp); } return(base.VisitAggregate(aggregate)); }
private object GetAggregatedValue(string key, AggregateExpression expression, IEnumerable <Dictionary <string, object> > group, EdmPrimitiveTypeKind edmPrimitiveType = EdmPrimitiveTypeKind.None, EdmComplexType edmComplexType = null) { var clrType = GetCLRTypeFromEdmType(edmPrimitiveType); var method = expression.Method; switch (method) { case AggregationMethod.Max: return(Convert.ChangeType(group.Max(r => r.GetValueOrDefault(key)), clrType)); case AggregationMethod.Min: return(Convert.ChangeType(group.Min(r => r.GetValueOrDefault(key)), clrType)); case AggregationMethod.Average: switch (edmPrimitiveType) { case EdmPrimitiveTypeKind.Double: return(group.Average(r => (double)r.GetValueOrDefault(key))); case EdmPrimitiveTypeKind.Int16: return(group.Average(r => (short)r.GetValueOrDefault(key))); case EdmPrimitiveTypeKind.Int32: return(group.Average(r => (int)r.GetValueOrDefault(key))); case EdmPrimitiveTypeKind.Int64: return(group.Average(r => (long)r.GetValueOrDefault(key))); case EdmPrimitiveTypeKind.Decimal: return(group.Average(r => (decimal)r.GetValueOrDefault(key))); default: return(group.Average(r => (int)r.GetValueOrDefault(key))); } case AggregationMethod.CountDistinct: return(group.Select(r => r.GetValueOrDefault(key)).Distinct().Count()); case AggregationMethod.VirtualPropertyCount: return(group.Select(r => r).Count()); case AggregationMethod.Sum: switch (edmPrimitiveType) { case EdmPrimitiveTypeKind.Double: return(group.Sum(r => (double)r.GetValueOrDefault(key))); case EdmPrimitiveTypeKind.Int16: return(group.Sum(r => (short)r.GetValueOrDefault(key))); case EdmPrimitiveTypeKind.Int32: return(group.Sum(r => (int)r.GetValueOrDefault(key))); case EdmPrimitiveTypeKind.Int64: return(group.Sum(r => (long)r.GetValueOrDefault(key))); case EdmPrimitiveTypeKind.Decimal: return(group.Sum(r => (decimal)r.GetValueOrDefault(key))); default: return(Convert.ChangeType(group.Sum(r => (int)r.GetValueOrDefault(key)), clrType)); } case AggregationMethod.Custom: return(ProcessCustomAggregationValue(expression.MethodDefinition.MethodLabel, group, edmComplexType, key)); } return(null); }
public virtual List <dynamic> Execute(AggregateExpression agg) { var queryResolver = _queryResolverFactory.Get(agg); var sqlString = queryResolver.ToSqlString(); List <string> selectFields = new List <string>(); foreach (var a in agg.AggregateFields) { selectFields.Add(DataFieldExpressionHelper.GetAggregationExpression(a.AggregateType, a.AttributeName) + " AS " + a.AttributeName); } sqlString = string.Format("SELECT {0} FROM ({1}) a", string.Join(",", selectFields).ToLower(), sqlString); return(_dataRepository.ExecuteQuery(sqlString, queryResolver.Parameters.Args.ToArray())); }
protected override Expression VisitAggregate(AggregateExpression aggregate) { switch (aggregate.AggregateName) { case "Average": this.WriteTruncMaxDecimalDigitsStart(); base.VisitAggregate(aggregate); this.WriteTruncMaxDecimalDigitsEnd(); break; default: return base.VisitAggregate(aggregate); } return aggregate; }
protected override Expression VisitAggregate(AggregateExpression aggregate) { switch (aggregate.AggregateName) { case "Average": this.WriteTruncMaxDecimalDigitsStart(); base.VisitAggregate(aggregate); this.WriteTruncMaxDecimalDigitsEnd(); break; default: return(base.VisitAggregate(aggregate)); } return(aggregate); }
protected override Expression VisitAggregate(AggregateExpression aggregate) { _sb.Append(GetAggregateName(aggregate.AggregateType)); _sb.Append("("); if (aggregate.Argument != null) { Visit(aggregate.Argument); } else if (aggregate.AggregateType == AggregateType.Count) { _sb.Append("*"); } _sb.Append(")"); return(aggregate); }
protected override Expression VisitAggregate(AggregateExpression aggregate) { string aggregateName = aggregate.AggregateName; if ((aggregateName != null) && (aggregateName == "Average")) { this.WriteTruncMaxDecimalDigitsStart(); base.VisitAggregate(aggregate); this.WriteTruncMaxDecimalDigitsEnd(); } else { return(base.VisitAggregate(aggregate)); } return(aggregate); }
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 virtual SqlFragment BuildAggregateSql(AggregateExpression expr) { if (expr.AggregateType == AggregateType.Count && expr.Operands.Count == 0) { return(this.SqlDialect.SqlCountStar); } SqlTemplate template = SqlDialect.GetAggregateTemplate(expr); if (template != null) { var args = expr.GetOperands(); var sqlArgs = args.Select(a => BuildLinqExpressionSql(a)).ToArray(); return(template.Format(sqlArgs)); } Util.Throw("Unsupported Aggregate type: {0}, expr: {1} ", expr.AggregateType, expr); return(null); }
protected override Expression VisitAggregate(AggregateExpression aggregate) { switch (aggregate.AggregateType) { case AggregateType.Average: _returnValues.Add(new KeyValuePair <string, string>(_currentAggregateName, string.Format("value.{0}Sum/value.{0}Cnt", _currentAggregateName))); break; case AggregateType.Count: case AggregateType.Max: case AggregateType.Min: case AggregateType.Sum: _returnValues.Add(new KeyValuePair <string, string>(_currentAggregateName, "value." + _currentAggregateName)); break; } return(aggregate); }
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); }
/// <summary> /// Visits the aggregate. /// </summary> /// <param name="aggregate">The aggregate.</param> /// <returns></returns> protected override Expression VisitAggregate(AggregateExpression aggregate) { this.WriteAggregateName(aggregate.AggregateName); this.Write("("); if (aggregate.IsDistinct) { this.Write("DISTINCT "); } if (aggregate.Argument != null) { this.VisitValue(aggregate.Argument); } else if (RequiresAsteriskWhenNoArgument(aggregate.AggregateName)) { this.Write("*"); } this.Write(")"); return(aggregate); }
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 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 IActionResult Post(AggregateModel model) { var queryView = _queryViewFinder.FindById(model.QueryViewId); if (queryView == null) { return(NotFound()); } if (queryView != null && queryView.AggregateConfig.IsNotEmpty()) { var aggFields = new List <AggregateExpressionField>().DeserializeFromJson(queryView.AggregateConfig); if (aggFields.NotEmpty()) { var queryExp = new QueryExpression().DeserializeFromJson(queryView.FetchConfig); if (model.Filter != null && (model.Filter.Conditions.NotEmpty() || (model.Filter.Filters.NotEmpty() && model.Filter.Filters.First().Conditions.NotEmpty()))) { queryExp.Criteria.AddFilter(model.Filter); } var aggExp = new AggregateExpression { ColumnSet = queryExp.ColumnSet, Criteria = queryExp.Criteria, EntityName = queryExp.EntityName, LinkEntities = queryExp.LinkEntities, AggregateFields = aggFields }; var aggDatas = _aggregateService.Execute(aggExp); var attributes = _attributeFinder.FindByName(queryView.EntityId, aggFields.Select(x => x.AttributeName).ToArray()); foreach (dynamic item in aggDatas) { var line = item as IDictionary <string, object>; var attribute = attributes.Find(x => x.Name.IsCaseInsensitiveEqual(line.Keys.First())); item.metadata = new { attribute.Name, attribute.LocalizedName, attribute.AttributeTypeName, attribute.EntityId, attribute.EntityName, attribute.EntityLocalizedName }; item.aggregatetype = aggFields.Find(x => x.AttributeName.IsCaseInsensitiveEqual(attribute.Name)).AggregateType; } return(JOk(new { View = new { queryView.QueryViewId, queryView.Name }, Data = aggDatas })); } } return(JOk()); }
private MethodInfo GetCustomMethod(AggregateExpression expression) { var propertyLambda = Expression.Lambda(BindAccessor(expression.Expression), this._lambdaParameter); Type inputType = propertyLambda.Body.Type; string methodToken = expression.MethodDefinition.MethodLabel; var customFunctionAnnotations = Model.GetAnnotationValue<CustomAggregateMethodAnnotation>(Model); MethodInfo customMethod; if (!customFunctionAnnotations.GetMethodInfo(methodToken, inputType, out customMethod)) { throw new ODataException( Error.Format( SRResources.AggregationNotSupportedForType, expression.Method, expression.Expression, inputType)); } return customMethod; }
protected override Expression VisitAggregate(AggregateExpression aggregate) { switch (aggregate.AggregateType) { case AggregateType.Average: _initMap[_currentAggregateName + "Sum"] = _formatter.FormatJavascript(aggregate.Argument); _initMap[_currentAggregateName + "Cnt"] = "1"; break; case AggregateType.Count: _initMap[_currentAggregateName] = "1"; break; case AggregateType.Max: case AggregateType.Min: case AggregateType.Sum: _initMap[_currentAggregateName] = _formatter.FormatJavascript(aggregate.Argument); break; } return(aggregate); }
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"); }
/// <summary> /// This is a hacky function to convert condition which under aggregated node and operator is IsNull /// for normal query, if the condition is under aggregated node, the queryBuilder will add this condition to child aggregate table. /// however for IsNull condition is little special, it should be in main where clause and the condition node should be current aggreagate node id. /// </summary> /// <param name="conditions">structuredQuery conditions</param> /// <param name="aggregateEntity">current aggregated entity</param> private void ConvertConditionExpressionToAggregate(List <QueryCondition> conditions, AggregateEntity aggregateEntity) { if (conditions.Any(c => c.Operator == ConditionType.IsNull && c.Expression is ResourceDataColumn && MatchGroupedEntityNode(((ResourceDataColumn)c.Expression).NodeId, aggregateEntity.GroupedEntity) )) { foreach (QueryCondition condition in conditions) { ResourceDataColumn resourceExpression = condition.Expression as ResourceDataColumn; if (resourceExpression != null) { AggregateExpression aggregateExpression = new AggregateExpression { AggregateMethod = AggregateMethod.Min, NodeId = aggregateEntity.NodeId, Expression = resourceExpression }; condition.Expression = aggregateExpression; } } } }
public static object GetValue(this IAggregateService aggregateService, string entityName, FilterExpression filter, AggregateType aggregateType) { var agg = new AggregateExpression { EntityName = entityName , AggregateFields = new List <AggregateExpressionField> { new AggregateExpressionField { AttributeName = entityName + "Id", AggregateType = aggregateType } } , Criteria = filter }; agg.AddColumns(entityName + "Id"); var values = aggregateService.Execute(agg); if (values.NotEmpty()) { return((values[0] as IDictionary <string, object>).Values.First()); } return(null); }
private Expression CreatePropertyAggregateExpression(ParameterExpression accum, AggregateExpression expression, Type baseType) { // accum type is IGrouping<,baseType> that implements IEnumerable<baseType> // we need cast it to IEnumerable<baseType> during expression building (IEnumerable)$it // however for EF6 we need to use $it.AsQueryable() due to limitations in types of casts that will properly translated Expression asQuerableExpression = null; if (_classicEF) { var asQuerableMethod = ExpressionHelperMethods.QueryableAsQueryable.MakeGenericMethod(baseType); asQuerableExpression = Expression.Call(null, asQuerableMethod, accum); } else { var queryableType = typeof(IEnumerable <>).MakeGenericType(baseType); asQuerableExpression = Expression.Convert(accum, queryableType); } // $count is a virtual property, so there's not a propertyLambda to create. if (expression.Method == AggregationMethod.VirtualPropertyCount) { var countMethod = (_classicEF ? ExpressionHelperMethods.QueryableCountGeneric : ExpressionHelperMethods.EnumerableCountGeneric).MakeGenericMethod(baseType); return(WrapConvert(Expression.Call(null, countMethod, asQuerableExpression))); } Expression body; var lambdaParameter = baseType == this._elementType ? this._lambdaParameter : Expression.Parameter(baseType, "$it"); if (!this._preFlattenedMap.TryGetValue(expression.Expression, out body)) { body = BindAccessor(expression.Expression, lambdaParameter); } LambdaExpression propertyLambda = Expression.Lambda(body, lambdaParameter); Expression aggregationExpression; switch (expression.Method) { case AggregationMethod.Min: { var minMethod = (_classicEF ? ExpressionHelperMethods.QueryableMin : ExpressionHelperMethods.EnumerableMin).MakeGenericMethod(baseType, propertyLambda.Body.Type); aggregationExpression = Expression.Call(null, minMethod, asQuerableExpression, propertyLambda); } break; case AggregationMethod.Max: { var maxMethod = (_classicEF ? ExpressionHelperMethods.QueryableMax : ExpressionHelperMethods.EnumerableMax).MakeGenericMethod(baseType, propertyLambda.Body.Type); aggregationExpression = Expression.Call(null, maxMethod, asQuerableExpression, propertyLambda); } break; case AggregationMethod.Sum: { MethodInfo sumGenericMethod; // For Dynamic properties cast to decimal Expression propertyExpression = WrapDynamicCastIfNeeded(body); propertyLambda = Expression.Lambda(propertyExpression, lambdaParameter); if ( !(_classicEF ? ExpressionHelperMethods.QueryableSumGenerics : ExpressionHelperMethods.EnumerableSumGenerics).TryGetValue(propertyExpression.Type, out sumGenericMethod)) { throw new ODataException(Error.Format(SRResources.AggregationNotSupportedForType, expression.Method, expression.Expression, propertyExpression.Type)); } var sumMethod = sumGenericMethod.MakeGenericMethod(baseType); aggregationExpression = Expression.Call(null, sumMethod, asQuerableExpression, propertyLambda); // For Dynamic properties cast back to object if (propertyLambda.Type == typeof(object)) { aggregationExpression = Expression.Convert(aggregationExpression, typeof(object)); } } break; case AggregationMethod.Average: { MethodInfo averageGenericMethod; // For Dynamic properties cast to decimal Expression propertyExpression = WrapDynamicCastIfNeeded(body); propertyLambda = Expression.Lambda(propertyExpression, lambdaParameter); if ( !(_classicEF ? ExpressionHelperMethods.QueryableAverageGenerics : ExpressionHelperMethods.EnumerableAverageGenerics).TryGetValue(propertyExpression.Type, out averageGenericMethod)) { throw new ODataException(Error.Format(SRResources.AggregationNotSupportedForType, expression.Method, expression.Expression, propertyExpression.Type)); } var averageMethod = averageGenericMethod.MakeGenericMethod(baseType); aggregationExpression = Expression.Call(null, averageMethod, asQuerableExpression, propertyLambda); // For Dynamic properties cast back to object if (propertyLambda.Type == typeof(object)) { aggregationExpression = Expression.Convert(aggregationExpression, typeof(object)); } } break; case AggregationMethod.CountDistinct: { // I select the specific field var selectMethod = (_classicEF ? ExpressionHelperMethods.QueryableSelectGeneric : ExpressionHelperMethods.EnumerableSelectGeneric).MakeGenericMethod(this._elementType, propertyLambda.Body.Type); Expression queryableSelectExpression = Expression.Call(null, selectMethod, asQuerableExpression, propertyLambda); // I run distinct over the set of items var distinctMethod = (_classicEF ? ExpressionHelperMethods.QueryableDistinct : ExpressionHelperMethods.EnumerableDistinct).MakeGenericMethod(propertyLambda.Body.Type); Expression distinctExpression = Expression.Call(null, distinctMethod, queryableSelectExpression); // I count the distinct items as the aggregation expression var countMethod = (_classicEF ? ExpressionHelperMethods.QueryableCountGeneric : ExpressionHelperMethods.EnumerableCountGeneric).MakeGenericMethod(propertyLambda.Body.Type); aggregationExpression = Expression.Call(null, countMethod, distinctExpression); } break; case AggregationMethod.Custom: { MethodInfo customMethod = GetCustomMethod(expression); var selectMethod = (_classicEF ? ExpressionHelperMethods.QueryableSelectGeneric : ExpressionHelperMethods.EnumerableSelectGeneric).MakeGenericMethod(this._elementType, propertyLambda.Body.Type); var selectExpression = Expression.Call(null, selectMethod, asQuerableExpression, propertyLambda); aggregationExpression = Expression.Call(null, customMethod, selectExpression); } break; default: throw new ODataException(Error.Format(SRResources.AggregationMethodNotSupported, expression.Method)); } return(WrapConvert(aggregationExpression)); }
/// <summary> /// Query for a single value. /// </summary> private static async Task Aggregate(RDXOeeKpiQuery rdxQuery, ContosoOpcUaNode opcUaNode, AggregateExpression expression) { opcUaNode.Last.Value = await rdxQuery.OpcUaQueries.GetAggregatedNode(rdxQuery.SearchSpan, rdxQuery.AppUri, opcUaNode.NodeId, expression); opcUaNode.Last.Time = rdxQuery.SearchSpan.To; opcUaNode.UpdateRelevance(rdxQuery.TopologyNode); }
protected override Expression VisitAggregate(AggregateExpression aggregate) { this.hasAggregate = true; return aggregate; }
protected override Expression VisitAggregate(AggregateExpression aggregate) { sb.Append(GetAggregateName(aggregate.AggregateType)); sb.Append("("); if (aggregate.IsDistinct) { sb.Append("DISTINCT "); } if (aggregate.Argument != null) { VisitValue(aggregate.Argument); } else if (RequiresAsteriskWhenNoArgument(aggregate.AggregateType)) { sb.Append("*"); } sb.Append(")"); return aggregate; }
protected override Expression VisitAggregate(AggregateExpression aggregate) { Expression source = MakeSqlValue(Visit(aggregate.Source)); if (source != aggregate.Source) return new AggregateExpression(aggregate.Type, source, aggregate.AggregateFunction); return aggregate; }
protected virtual bool CompareAggregate(AggregateExpression a, AggregateExpression b) { return a.AggregateName == b.AggregateName && this.Compare(a.Argument, b.Argument); }
protected virtual Expression VisitAggregate(AggregateExpression aggregate) { var arg = this.Visit(aggregate.Argument); return this.UpdateAggregate(aggregate, aggregate.Type, aggregate.AggregateName, arg, aggregate.IsDistinct); }
protected override Expression VisitAggregate(AggregateExpression aggregate) { hasAggregates = true; return base.VisitAggregate(aggregate); }
private bool CompareAggregate(AggregateExpression a, AggregateExpression b) { return a.AggregateName == b.AggregateName && this.Compare(a.Argument, b.Argument); }
private Expression BindAggregate(Expression source, MethodInfo method, LambdaExpression argument, bool isRoot) { Type returnType = method.ReturnType; AggregateType aggType = GetAggregateType(method.Name); bool hasPredicateArg = HasPredicateArg(aggType); bool isDistinct = false; bool argumentWasPredicate = false; bool useAlternateArg = false; // check for distinct MethodCallExpression mcs = source as MethodCallExpression; if (mcs != null && !hasPredicateArg && argument == null) { if (mcs.Method.Name == "Distinct" && mcs.Arguments.Count == 1 && (mcs.Method.DeclaringType == typeof(Queryable) || mcs.Method.DeclaringType == typeof(Enumerable))) { source = mcs.Arguments[0]; isDistinct = true; } } if (argument != null && hasPredicateArg) { // convert query.Count(predicate) into query.Where(predicate).Count() source = Expression.Call(typeof(Queryable), "Where", method.GetGenericArguments(), source, argument); argument = null; argumentWasPredicate = true; } ProjectionExpression projection = VisitSequence(source); Expression argExpr = null; if (argument != null) { map[argument.Parameters[0]] = projection.Projector; argExpr = Visit(argument.Body); } else if (!hasPredicateArg || useAlternateArg) { argExpr = projection.Projector; } var alias = GetNextAlias(); var pc = ProjectColumns(projection.Projector, alias, projection.Source.Alias); Expression aggExpr = new AggregateExpression(returnType, aggType, argExpr, isDistinct); SelectExpression select = new SelectExpression(alias, new[] { new ColumnDeclaration("", aggExpr) }, projection.Source, null); if (isRoot) { ParameterExpression p = Expression.Parameter(typeof(IEnumerable <>).MakeGenericType(aggExpr.Type), "p"); LambdaExpression gator = Expression.Lambda(Expression.Call(typeof(Enumerable), "Single", new[] { returnType }, p), p); return(new ProjectionExpression(select, new ColumnExpression(returnType, alias, ""), gator)); } ScalarExpression subquery = new ScalarExpression(returnType, select); // if we can find the corresponding group-info we can build a special AggregateSubquery node that will enable us to // optimize the aggregate expression later using AggregateRewriter GroupByInfo info; if (!argumentWasPredicate && groupByMap.TryGetValue(projection, out info)) { // use the element expression from the group-by info to rebind the argument so the resulting expression is one that // would be legal to add to the columns in the select expression that has the corresponding group-by clause. if (argument != null) { map[argument.Parameters[0]] = info.Element; argExpr = Visit(argument.Body); } else if (!hasPredicateArg || useAlternateArg) { argExpr = info.Element; } aggExpr = new AggregateExpression(returnType, aggType, argExpr, isDistinct); // check for easy to optimize case. If the projection that our aggregate is based on is really the 'group' argument from // the query.GroupBy(xxx, (key, group) => yyy) method then whatever expression we return here will automatically // become part of the select expression that has the group-by clause, so just return the simple aggregate expression. if (projection == currentGroupElement) { return(aggExpr); } return(new AggregateSubqueryExpression(info.Alias, aggExpr, subquery)); } return(subquery); }
private Expression BindAggregate(Expression source, MethodInfo method, LambdaExpression argument, bool isRoot) { var returnType = method.ReturnType; var aggregateType = GetAggregateType(method.Name); bool hasPredicateArgument = HasPredicateArgument(aggregateType); bool distinct = false; bool argumentWasPredicate = false; var methodCallExpression = source as MethodCallExpression; if (methodCallExpression != null && !hasPredicateArgument && argument == null) { if (methodCallExpression.Method.Name == "Distinct" && methodCallExpression.Arguments.Count == 1 && (methodCallExpression.Method.DeclaringType == typeof(Queryable) || methodCallExpression.Method.DeclaringType == typeof(Enumerable))) { source = methodCallExpression.Arguments[0]; distinct = true; } } if (argument != null && hasPredicateArgument) { source = Expression.Call(typeof(Queryable), "Where", method.GetGenericArguments(), source, argument); argument = null; argumentWasPredicate = true; } var projection = VisitSequence(source); Expression argExpression = null; if (argument != null) { _map[argument.Parameters[0]] = projection.Projector; argExpression = Visit(argument.Body); } else if (!hasPredicateArgument) { argExpression = projection.Projector; } var alias = new Alias(); Expression aggregateExpression = new AggregateExpression(returnType, aggregateType, argExpression, distinct); var selectType = typeof(IEnumerable <>).MakeGenericType(returnType); string fieldName = "_$agg" + (_aggregateCount++); var select = new SelectExpression(alias, new[] { new FieldDeclaration(fieldName, aggregateExpression) }, projection.Source, null); if (isRoot) { var parameter = Expression.Parameter(selectType, "p"); var lambda = Expression.Lambda(Expression.Call(typeof(Enumerable), "Single", new[] { returnType }, parameter), parameter); return(new ProjectionExpression( select, new FieldExpression(aggregateExpression, alias, fieldName), lambda)); } var subquery = new ScalarExpression(returnType, select); GroupByInfo info; if (!argumentWasPredicate && _groupByMap.TryGetValue(projection, out info)) { if (argument != null) { _map[argument.Parameters[0]] = info.Element; argExpression = Visit(argument.Body); } else if (!hasPredicateArgument) { argExpression = info.Element; } aggregateExpression = new AggregateExpression(returnType, aggregateType, argExpression, distinct); if (projection == _currentGroupElement) { return(aggregateExpression); } return(new AggregateSubqueryExpression(info.Alias, aggregateExpression, subquery)); } return(subquery); }
protected virtual bool CompareAggregate(AggregateExpression a, AggregateExpression b) { return(a.AggregateType == b.AggregateType && Compare(a.Argument, b.Argument)); }
protected virtual Expression VisitAggregate(AggregateExpression aggregate) { Expression source = Visit(aggregate.Source); if (source != aggregate.Source) return new AggregateExpression(aggregate.Type, source, aggregate.AggregateFunction); return aggregate; }
protected override Expression VisitAggregate(AggregateExpression aggregate) { this.WriteAggregateName(aggregate.AggregateName); this.Write("("); if (aggregate.IsDistinct) { this.Write("DISTINCT "); } if (aggregate.Argument != null) { this.VisitValue(aggregate.Argument); } else if (RequiresAsteriskWhenNoArgument(aggregate.AggregateName)) { this.Write("*"); } this.Write(")"); return aggregate; }
private Expression BindAggregate(Expression source, string aggName, Type returnType, LambdaExpression argument, bool isRoot) { bool hasPredicateArg = this.language.AggregateArgumentIsPredicate(aggName); bool isDistinct = false; bool argumentWasPredicate = false; bool useAlternateArg = false; // check for distinct MethodCallExpression mcs = source as MethodCallExpression; if (mcs != null && !hasPredicateArg && argument == null) { if (mcs.Method.Name == "Distinct" && mcs.Arguments.Count == 1 && (mcs.Method.DeclaringType == typeof(Queryable) || mcs.Method.DeclaringType == typeof(Enumerable)) && this.language.AllowDistinctInAggregates) { source = mcs.Arguments[0]; isDistinct = true; } } if (argument != null && hasPredicateArg) { // convert query.Count(predicate) into query.Where(predicate).Count() source = Expression.Call(typeof(Queryable), "Where", new[] { TypeHelper.GetElementType(source.Type) }, source, argument); argument = null; argumentWasPredicate = true; } ProjectionExpression projection = this.VisitSequence(source); Expression argExpr = null; if (argument != null) { this.map[argument.Parameters[0]] = projection.Projector; argExpr = this.Visit(argument.Body); } else if (!hasPredicateArg || useAlternateArg) { argExpr = projection.Projector; } var alias = this.GetNextAlias(); var pc = this.ProjectColumns(projection.Projector, alias, projection.Select.Alias); Expression aggExpr = new AggregateExpression(returnType, aggName, argExpr, isDistinct); var colType = this.language.TypeSystem.GetColumnType(returnType); SelectExpression select = new SelectExpression(alias, new ColumnDeclaration[] { new ColumnDeclaration("", aggExpr, colType) }, projection.Select, null); if (isRoot) { ParameterExpression p = Expression.Parameter(typeof(IEnumerable<>).MakeGenericType(aggExpr.Type), "p"); LambdaExpression gator = Expression.Lambda(Expression.Call(typeof(Enumerable), "Single", new Type[] { returnType }, p), p); return new ProjectionExpression(select, new ColumnExpression(returnType, this.language.TypeSystem.GetColumnType(returnType), alias, ""), gator); } ScalarExpression subquery = new ScalarExpression(returnType, select); // if we can find the corresponding group-info we can build a special AggregateSubquery node that will enable us to // optimize the aggregate expression later using AggregateRewriter GroupByInfo info; if (!argumentWasPredicate && this.groupByMap.TryGetValue(projection, out info)) { // use the element expression from the group-by info to rebind the argument so the resulting expression is one that // would be legal to add to the columns in the select expression that has the corresponding group-by clause. if (argument != null) { this.map[argument.Parameters[0]] = info.Element; argExpr = this.Visit(argument.Body); } else if (!hasPredicateArg || useAlternateArg) { argExpr = info.Element; } aggExpr = new AggregateExpression(returnType, aggName, argExpr, isDistinct); // check for easy to optimize case. If the projection that our aggregate is based on is really the 'group' argument from // the query.GroupBy(xxx, (key, group) => yyy) method then whatever expression we return here will automatically // become part of the select expression that has the group-by clause, so just return the simple aggregate expression. if (projection == this.currentGroupElement) return aggExpr; return new AggregateSubqueryExpression(info.Alias, aggExpr, subquery); } return subquery; }
private Expression CreateAggregationExpression(ParameterExpression accum, AggregateExpression expression) { // I substitute the element type for all generic arguments. var asQuerableMethod = ExpressionHelperMethods.QueryableAsQueryable.MakeGenericMethod(this._elementType); Expression asQuerableExpression = Expression.Call(null, asQuerableMethod, accum); // $count is a virtual property, so there's not a propertyLambda to create. if (expression.Method == AggregationMethod.VirtualPropertyCount) { var countMethod = ExpressionHelperMethods.QueryableCountGeneric.MakeGenericMethod(this._elementType); return(this.WrapConvert(Expression.Call(null, countMethod, asQuerableExpression))); } LambdaExpression propertyLambda = Expression.Lambda(this.BindAccessor(expression.Expression), this._lambdaParameter); Expression aggregationExpression; switch (expression.Method) { case AggregationMethod.Min: { var minMethod = ExpressionHelperMethods.QueryableMin.MakeGenericMethod(this._elementType, propertyLambda.Body.Type); aggregationExpression = Expression.Call(null, minMethod, asQuerableExpression, propertyLambda); } break; case AggregationMethod.Max: { var maxMethod = ExpressionHelperMethods.QueryableMax.MakeGenericMethod(this._elementType, propertyLambda.Body.Type); aggregationExpression = Expression.Call(null, maxMethod, asQuerableExpression, propertyLambda); } break; case AggregationMethod.Sum: { MethodInfo sumGenericMethod; if ( !ExpressionHelperMethods.QueryableSumGenerics.TryGetValue(propertyLambda.Body.Type, out sumGenericMethod)) { throw new ODataException(Error.Format(SRResources.AggregationNotSupportedForType, expression.Method, expression.Expression, propertyLambda.Body.Type)); } var sumMethod = sumGenericMethod.MakeGenericMethod(this._elementType); aggregationExpression = Expression.Call(null, sumMethod, asQuerableExpression, propertyLambda); } break; case AggregationMethod.Average: { MethodInfo averageGenericMethod; if ( !ExpressionHelperMethods.QueryableAverageGenerics.TryGetValue(propertyLambda.Body.Type, out averageGenericMethod)) { throw new ODataException(Error.Format(SRResources.AggregationNotSupportedForType, expression.Method, expression.Expression, propertyLambda.Body.Type)); } var averageMethod = averageGenericMethod.MakeGenericMethod(this._elementType); aggregationExpression = Expression.Call(null, averageMethod, asQuerableExpression, propertyLambda); } break; case AggregationMethod.CountDistinct: { // I select the specific field var selectMethod = ExpressionHelperMethods.QueryableSelectGeneric.MakeGenericMethod(this._elementType, propertyLambda.Body.Type); Expression queryableSelectExpression = Expression.Call(null, selectMethod, asQuerableExpression, propertyLambda); // I run distinct over the set of items var distinctMethod = ExpressionHelperMethods.QueryableDistinct.MakeGenericMethod(propertyLambda.Body.Type); Expression distinctExpression = Expression.Call(null, distinctMethod, queryableSelectExpression); // I count the distinct items as the aggregation expression var countMethod = ExpressionHelperMethods.QueryableCountGeneric.MakeGenericMethod(propertyLambda.Body.Type); aggregationExpression = Expression.Call(null, countMethod, distinctExpression); } break; case AggregationMethod.Custom: { MethodInfo customMethod = this.GetCustomMethod(expression); var selectMethod = ExpressionHelperMethods.QueryableSelectGeneric.MakeGenericMethod(this._elementType, propertyLambda.Body.Type); var selectExpression = Expression.Call(null, selectMethod, asQuerableExpression, propertyLambda); aggregationExpression = Expression.Call(null, customMethod, selectExpression); } break; default: throw new ODataException(Error.Format(SRResources.AggregationMethodNotSupported, expression.Method)); } return(this.WrapConvert(aggregationExpression)); }
protected override Expression VisitAggregate(AggregateExpression aggregate) { sb.Append(dic[aggregate.AggregateFunction]); sb.Append("("); if (aggregate.Source == null) sb.Append("*"); else Visit(aggregate.Source); sb.Append(")"); return aggregate; }