public Expression Bind(PipelineExpression pipeline, PipelineBindingContext bindingContext, MethodCallExpression node, IEnumerable <Expression> arguments) { var source = pipeline.Source; if (arguments.Any()) { source = BinderHelper.BindWhere( pipeline, bindingContext, ExpressionHelper.GetLambda(arguments.Single())); } var serializer = bindingContext.GetSerializer(node.Type, null); var accumulator = new AccumulatorExpression( node.Type, "__result", serializer, AccumulatorType.Sum, Expression.Constant(1)); source = new GroupByExpression( node.Type, source, Expression.Constant(1), new[] { accumulator }); return(new PipelineExpression( source, new FieldExpression(accumulator.FieldName, accumulator.Serializer), new CountResultOperator( node.Type, bindingContext.GetSerializer(node.Type, node)))); }
protected override Expression VisitNew(NewExpression node) { var newNode = (NewExpression)base.VisitNew(node); if (newNode.Type.IsGenericType && newNode.Type.GetGenericTypeDefinition() == typeof(HashSet <>) && newNode.Arguments.Count == 1 && newNode.Arguments[0] is AccumulatorExpression && ((AccumulatorExpression)newNode.Arguments[0]).AccumulatorType == AccumulatorType.Push) { Guid correlationId = Guid.Empty; if (_groupMap == null || TryGetCorrelatedGroup(node.Arguments[0], out correlationId)) { Expression accumulator = new AccumulatorExpression( newNode.Type, AccumulatorType.AddToSet, ((AccumulatorExpression)newNode.Arguments[0]).Argument); if (_groupMap != null) { accumulator = new CorrelatedAccumulatorExpression( correlationId, (AccumulatorExpression)accumulator); } return(accumulator); } } return(newNode); }
private bool TryBindAccumulatorExpression(MethodCallExpression node, out Expression accumulator) { AccumulatorType accumulatorType; if (TryGetAccumulatorType(node.Method.Name, out accumulatorType)) { Guid correlationId = Guid.Empty; if (_groupMap == null || TryGetCorrelatedGroup(node.Arguments[0], out correlationId)) { accumulator = new AccumulatorExpression(node.Type, accumulatorType, GetAccumulatorArgument(node)); if (_groupMap != null) { accumulator = new CorrelatedAccumulatorExpression( correlationId, (AccumulatorExpression)accumulator); } return(true); } } accumulator = null; return(false); }
protected internal override Expression VisitPipeline(PipelineExpression node) { Guid correlationId; if (TryGetCorrelatedGroup(node.Source, out correlationId)) { AccumulatorType accumulatorType; Expression argument; if (TryGetAccumulatorTypeAndArgument(node, out accumulatorType, out argument)) { var accumulator = new AccumulatorExpression( node.Type, "__agg" + _count++, _bindingContext.GetSerializer(node.Type, argument), accumulatorType, argument); return(new CorrelatedExpression( correlationId, accumulator)); } } return(node); }
public override Expression Bind(ProjectionExpression projection, ProjectionBindingContext context, MethodCallExpression node, IEnumerable <Expression> arguments) { var aggregatorName = "SingleOrDefault"; var returnType = node.Method.ReturnType; if (node.Method.Name.EndsWith("Async")) { aggregatorName += "Async"; returnType = returnType.GetGenericArguments()[0]; // it's a task } var aggregator = CreateAggregator(aggregatorName, returnType); var source = projection.Source; var argument = arguments.FirstOrDefault(); if (argument != null && ExtensionExpressionVisitor.IsLambda(argument)) { source = BindPredicate(projection, context, source, argument); } var serializer = context.SerializerRegistry.GetSerializer(returnType); var accumulator = new AccumulatorExpression(returnType, AccumulatorType.Count, null); var serializationAccumulator = new SerializationExpression( accumulator, new BsonSerializationInfo("__agg0", serializer, serializer.ValueType)); var rootAccumulator = new RootAccumulatorExpression(source, serializationAccumulator); return(new ProjectionExpression( rootAccumulator, serializationAccumulator, aggregator)); }
private BsonValue TranslateAccumulator(AccumulatorExpression node) { switch (node.AccumulatorType) { case AccumulatorType.AddToSet: return(new BsonDocument("$addToSet", TranslateValue(node.Argument))); case AccumulatorType.Average: return(new BsonDocument("$avg", TranslateValue(node.Argument))); case AccumulatorType.First: return(new BsonDocument("$first", TranslateValue(node.Argument))); case AccumulatorType.Last: return(new BsonDocument("$last", TranslateValue(node.Argument))); case AccumulatorType.Max: return(new BsonDocument("$max", TranslateValue(node.Argument))); case AccumulatorType.Min: return(new BsonDocument("$min", TranslateValue(node.Argument))); case AccumulatorType.Push: return(new BsonDocument("$push", TranslateValue(node.Argument))); case AccumulatorType.Sum: return(new BsonDocument("$sum", TranslateValue(node.Argument))); } // we should never ever get here. var message = string.Format("Unrecognized aggregation type in the expression tree {0}.", node.ToString()); throw new MongoInternalException(message); }
public Expression Bind(PipelineExpression pipeline, PipelineBindingContext bindingContext, MethodCallExpression node, IEnumerable <Expression> arguments) { var source = pipeline.Source; Expression argument; if (arguments.Any()) { var lambda = ExpressionHelper.GetLambda(arguments.Single()); bindingContext.AddExpressionMapping(lambda.Parameters[0], pipeline.Projector); argument = bindingContext.Bind(lambda.Body); } else { var selectExpression = source as SelectExpression; if (selectExpression != null) { source = selectExpression.Source; argument = selectExpression.Selector; var fieldAsDocumentExpression = argument as FieldAsDocumentExpression; if (fieldAsDocumentExpression != null) { argument = fieldAsDocumentExpression.Expression; } } else { argument = pipeline.Projector; } } var serializer = bindingContext.GetSerializer(node.Type, argument); var accumulator = new AccumulatorExpression( node.Type, "__result", serializer, GetAccumulatorType(), argument); source = new GroupByExpression( node.Type, source, Expression.Constant(1), new[] { accumulator }); return(new PipelineExpression( source, new FieldExpression(accumulator.FieldName, accumulator.Serializer), CreateResultOperator( node.Type, bindingContext.GetSerializer(node.Type, node)))); }
private Expression VisitCorrelatedGroup(CorrelatedExpression node) { var groupExpression = (GroupByExpression)node.Expression; if (_accumulatorLookup != null && _accumulatorLookup.Contains(node.CorrelationId)) { var oldAccumulatorLookup = _accumulatorLookup; var source = Visit(groupExpression.Source); _accumulatorLookup = oldAccumulatorLookup; var accumulators = new List <AccumulatorExpression>(); var fieldExpressions = new List <FieldExpression>(); var comparer = new ExpressionComparer(); foreach (var correlatedAccumulator in _accumulatorLookup[node.CorrelationId]) { var index = accumulators.FindIndex(x => comparer.Compare((Expression)x, correlatedAccumulator.Expression)); FieldExpression fieldExpression; if (index == -1) { var accumulator = (AccumulatorExpression)correlatedAccumulator.Expression; // TODO: might not need to do any renames... accumulator = new AccumulatorExpression( accumulator.Type, "__agg" + accumulators.Count, accumulator.Serializer, accumulator.AccumulatorType, accumulator.Argument); accumulators.Add(accumulator); fieldExpression = new FieldExpression(accumulator.FieldName, accumulator.Serializer); fieldExpressions.Add(fieldExpression); } else { fieldExpression = fieldExpressions[index]; } _accumulatorReplacementMap[correlatedAccumulator] = fieldExpression; } groupExpression = new GroupByExpression( groupExpression.Type, source, groupExpression.KeySelector, accumulators.AsReadOnly()); } return(Visit(groupExpression)); }
private bool TryBindAccumulatorExpression(MethodCallExpression node, out AccumulatorExpression accumulator) { AccumulatorType accumulatorType; if (TryGetAccumulatorType(node.Method.Name, out accumulatorType)) { var argument = GetAccumulatorArgument(node); accumulator = new AccumulatorExpression(node.Type, accumulatorType, argument); return(true); } accumulator = null; return(false); }
public override Expression Bind(Expressions.ProjectionExpression projection, ProjectionBindingContext context, System.Linq.Expressions.MethodCallExpression node, IEnumerable <System.Linq.Expressions.Expression> arguments) { var aggregatorName = "Single"; var returnType = node.Method.ReturnType; if (node.Method.Name.EndsWith("Async")) { aggregatorName += "Async"; returnType = returnType.GetGenericArguments()[0]; } var aggregator = CreateAggregator(aggregatorName, returnType); var source = projection.Source; var argument = arguments.FirstOrDefault(); if (argument != null && ExtensionExpressionVisitor.IsLambda(argument)) { var lambda = ExtensionExpressionVisitor.GetLambda(argument); var binder = new AccumulatorBinder(context.GroupMap, context.SerializerRegistry); binder.RegisterParameterReplacement(lambda.Parameters[0], projection.Projector); argument = binder.Bind(lambda.Body); } else { argument = projection.Projector; var select = source as SelectExpression; if (select != null) { source = select.Source; } } var serializer = context.SerializerRegistry.GetSerializer(returnType); var accumulator = new AccumulatorExpression(returnType, AccumulatorType, argument); var serializationAccumulator = new SerializationExpression( accumulator, new BsonSerializationInfo("__agg0", serializer, serializer.ValueType)); var rootAccumulator = new RootAccumulatorExpression(source, serializationAccumulator); return(new ProjectionExpression( rootAccumulator, serializationAccumulator, aggregator)); }
public override Expression Bind(ProjectionExpression projection, ProjectionBindingContext context, MethodCallExpression node, IEnumerable <Expression> arguments) { LambdaExpression aggregator; if (node.Method.Name.EndsWith("Async")) { aggregator = CreateAsyncAggregator(); } else { aggregator = CreateSyncAggregator(); } var source = projection.Source; var argument = arguments.FirstOrDefault(); if (argument != null && ExtensionExpressionVisitor.IsLambda(argument)) { source = BindPredicate(projection, context, source, argument); } source = new TakeExpression(source, 1); var serializer = context.SerializerRegistry.GetSerializer(typeof(int)); var accumulator = new AccumulatorExpression(typeof(int), AccumulatorType.Count, null); var serializationAccumulator = new SerializationExpression( accumulator, new BsonSerializationInfo("__agg0", serializer, serializer.ValueType)); var rootAccumulator = new RootAccumulatorExpression(source, serializationAccumulator); return(new ProjectionExpression( rootAccumulator, serializationAccumulator, aggregator)); }
protected internal override Expression VisitAccumulator(AccumulatorExpression node) { return(node); }