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))));
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
        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);
        }
Esempio n. 5
0
        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));
        }
Esempio n. 6
0
        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))));
        }
Esempio n. 8
0
        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);
        }
Esempio n. 10
0
        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));
        }
Esempio n. 11
0
        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));
        }
Esempio n. 12
0
 protected internal override Expression VisitAccumulator(AccumulatorExpression node)
 {
     return(node);
 }