public AggregateExpression Sum(SparqlExpression expression) { var sumAggregate = new SumAggregate(expression.Expression, _distinctAggregate); return(new AggregateExpression(sumAggregate)); }
internal static List <Entity> ProcessAggregateFetchXml(XrmFakedContext ctx, XDocument xmlDoc, List <Entity> resultOfQuery) { // Validate that <all-attributes> is not present, // that all attributes have groupby or aggregate, and an alias, // and that there is exactly 1 groupby. if (RetrieveFetchXmlNode(xmlDoc, "all-attributes") != null) { throw new Exception("Can't have <all-attributes /> present when using aggregate"); } var ns = xmlDoc.Root.Name.Namespace; var entityName = RetrieveFetchXmlNode(xmlDoc, "entity")?.GetAttribute("name")?.Value; if (string.IsNullOrEmpty(entityName)) { throw new Exception("Can't find entity name for aggregate query"); } var aggregates = new List <FetchAggregate>(); var groups = new List <FetchGrouping>(); foreach (var attr in xmlDoc.Descendants(ns + "attribute")) { //TODO: Find entity alias. Handle aliasedvalue in the query result. var alias = attr.GetAttribute("alias")?.Value; var logicalName = attr.GetAttribute("name")?.Value; if (string.IsNullOrEmpty("alias")) { throw new Exception("Missing alias for attribute in aggregate fetch xml"); } if (string.IsNullOrEmpty("name")) { throw new Exception("Missing name for attribute in aggregate fetch xml"); } if (attr.IsAttributeTrue("groupby")) { var dategrouping = attr.GetAttribute("dategrouping")?.Value; if (dategrouping != null) { DateGroupType t; if (!Enum.TryParse(dategrouping, true, out t)) { throw new Exception("Unknown dategrouping value '" + dategrouping + "'"); } groups.Add(new DateTimeGroup() { Type = t, OutputAlias = alias, Attribute = logicalName }); } else { groups.Add(new SimpleValueGroup() { OutputAlias = alias, Attribute = logicalName }); } } else { var agrFn = attr.GetAttribute("aggregate")?.Value; if (string.IsNullOrEmpty(agrFn)) { throw new Exception("Attributes must have be aggregated or grouped by when using aggregation"); } FetchAggregate newAgr = null; switch (agrFn?.ToLower()) { case "count": newAgr = new CountAggregate(); break; case "countcolumn": if (attr.IsAttributeTrue("distinct")) { newAgr = new CountDistinctAggregate(); } else { newAgr = new CountColumnAggregate(); } break; case "min": newAgr = new MinAggregate(); break; case "max": newAgr = new MaxAggregate(); break; case "avg": newAgr = new AvgAggregate(); break; case "sum": newAgr = new SumAggregate(); break; default: throw new Exception("Unknown aggregate function '" + agrFn + "'"); } newAgr.OutputAlias = alias; newAgr.Attribute = logicalName; aggregates.Add(newAgr); } } List <Entity> aggregateResult; if (groups.Any()) { aggregateResult = ProcessGroupedAggregate(entityName, resultOfQuery, aggregates, groups); } else { aggregateResult = new List <Entity>(); var ent = ProcessAggregatesForSingleGroup(entityName, resultOfQuery, aggregates); aggregateResult.Add(ent); } return(OrderAggregateResult(xmlDoc, aggregateResult.AsQueryable())); }
public AggregateExpression Sum(VariableTerm variable) { var sumAggregate = new SumAggregate(variable, _distinctAggregate); return(new AggregateExpression(sumAggregate)); }
public override void SetObjectOperator(ResultOperatorBase resultOperator) { base.SetObjectOperator(resultOperator); if (ObjectVariable != null) { if (resultOperator is AnyResultOperator) { // When using x.Any(), we add a LIMIT 1 the query results in the SparqlQueryGenerator. // When using .Any(x => ..), the variable x is locally scoped and cannot be // used in outer queries. Therefore do not need to actually select it. // This avoids issues with Stardog: // https://community.stardog.com/t/sparql-union-only-working-with-inferencing-enabled/1040/9 } else if (resultOperator is AverageResultOperator) { var aggregate = new AverageAggregate(new VariableTerm(ObjectVariable.Name)); SetObjectVariable(aggregate.AsSparqlVariable(), true); } else if (resultOperator is CountResultOperator) { var aggregate = new CountDistinctAggregate(new VariableTerm(ObjectVariable.Name)); SetObjectVariable(aggregate.AsSparqlVariable(), true); } else if (resultOperator is FirstResultOperator) { // "Using LIMIT and OFFSET to select different subsets of the query solutions // will not be useful unless the order is made predictable by using ORDER BY." // Source: https://www.w3.org/TR/2013/REC-sparql11-query-20130321/#modOffset // Therefore, if no ordering exists we add an ordering on the current subject // to make the query result predictable. if (!QueryModel.BodyClauses.OfType <OrderByClause>().Any()) { OrderBy(SubjectVariable); } else { // In case the order was make explicit, we have to do nothing. } Limit(1); } else if (resultOperator is LastResultOperator) { // "Using LIMIT and OFFSET to select different subsets of the query solutions // will not be useful unless the order is made predictable by using ORDER BY." // Source: https://www.w3.org/TR/2013/REC-sparql11-query-20130321/#modOffset // Therefore, if no ordering exists we add an ordering on the current subject // to make the query result predictable. if (!QueryModel.BodyClauses.OfType <OrderByClause>().Any()) { OrderByDescending(SubjectVariable); } else { // Inverting the direction of the first ordering is handled in SparqlQueryModelVisitor.VisitOrdering(). // This is because the orderings are not necessarily processed *before* the result operators.. } Limit(1); } else if (resultOperator is MaxResultOperator) { var aggregate = new MaxAggregate(new VariableTerm(ObjectVariable.Name)); SetObjectVariable(aggregate.AsSparqlVariable(), true); } else if (resultOperator is MinResultOperator) { var aggregate = new MinAggregate(new VariableTerm(ObjectVariable.Name)); SetObjectVariable(aggregate.AsSparqlVariable(), true); } else if (resultOperator is SumResultOperator) { var aggregate = new SumAggregate(new VariableTerm(ObjectVariable.Name)); SetObjectVariable(aggregate.AsSparqlVariable(), true); } else if (resultOperator is OfTypeResultOperator) { OfTypeResultOperator ofType = resultOperator as OfTypeResultOperator; RdfClassAttribute type = ofType.SearchedItemType.TryGetCustomAttribute <RdfClassAttribute>(); if (type == null) { throw new ArgumentException("No RdfClass attrribute declared on type: " + ofType.SearchedItemType); } SparqlVariable s = ObjectVariable; SparqlVariable p = VariableGenerator.CreatePredicateVariable(); SparqlVariable o = VariableGenerator.CreateObjectVariable(); WhereResource(s, p, o); WhereResourceOfType(o, ofType.SearchedItemType); } else if (resultOperator is SkipResultOperator) { SkipResultOperator op = resultOperator as SkipResultOperator; Offset(int.Parse(op.Count.ToString())); } else if (resultOperator is TakeResultOperator) { TakeResultOperator op = resultOperator as TakeResultOperator; Limit(int.Parse(op.Count.ToString())); } else { throw new NotImplementedException(resultOperator.ToString()); } } }