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 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;
        }
Exemple #3
0
        public CorrelatedAccumulatorExpression Update(AccumulatorExpression accumulator)
        {
            if (accumulator != _accumulator)
            {
                return(new CorrelatedAccumulatorExpression(_correlationId, accumulator));
            }

            return(this);
        }
        public CorrelatedAccumulatorExpression Update(AccumulatorExpression accumulator)
        {
            if (accumulator != _accumulator)
            {
                return new CorrelatedAccumulatorExpression(_correlationId, accumulator);
            }

            return this;
        }
        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);
        }
        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;
        }
 protected internal virtual Expression VisitAccumulator(AccumulatorExpression node)
 {
     return(node.Update(Visit(node.Argument)));
 }
Exemple #8
0
 public CorrelatedAccumulatorExpression(Guid correlationId, AccumulatorExpression accumulator)
 {
     _correlationId = correlationId;
     _accumulator   = Ensure.IsNotNull(accumulator, "accumulator");
 }
 protected internal virtual Expression VisitAccumulator(AccumulatorExpression node)
 {
     return node.Update(Visit(node.Argument));
 }
        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.StandardDeviationPopulation:
                    return new BsonDocument("$stdDevPop", TranslateValue(node.Argument));
                case AccumulatorType.StandardDeviationSample:
                    return new BsonDocument("$stdDevSamp", 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 CorrelatedAccumulatorExpression(Guid correlationId, AccumulatorExpression accumulator)
 {
     _correlationId = correlationId;
     _accumulator = Ensure.IsNotNull(accumulator, "accumulator");
 }
Exemple #12
0
 // private methods
 private bool CompareAccumulator(AccumulatorExpression a, AccumulatorExpression b)
 {
     return(a.AccumulatorType == b.AccumulatorType &&
            Compare(a.Argument, b.Argument));
 }
 protected internal override Expression VisitAccumulator(AccumulatorExpression node)
 {
     return node;
 }
        private Expression VisitCorrelatedGroup(CorrelatedExpression node)
        {
            var groupExpression = (GroupByExpression)node.Expression;
            if (_accumulatorLookup != null && _accumulatorLookup.Contains(node.CorrelationId))
            {
                var source = Visit(groupExpression.Source);
                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 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;
        }