public override Expression Bind(ProjectionExpression projection, ProjectionBindingContext context, MethodCallExpression node, IEnumerable<Expression> arguments)
        {
            // OfType is two operations in one. First we create WhereExpression
            // for the test.  Second, we want to issue a conversion projection 
            // using the selector parameter of a ProjectionExpression such that
            // the conversion will be propogated to all future expressions.

            var newType = node.Method.GetGenericArguments()[0];

            var parameter = Expression.Parameter(projection.Projector.Type);
            var predicate = Expression.Lambda(
                Expression.TypeIs(parameter, newType),
                parameter);

            var source = BindPredicate(projection, context, projection.Source, predicate);

            var serializer = context.SerializerRegistry.GetSerializer(newType);
            var info = new BsonSerializationInfo(null, serializer, newType);

            var projector = new SerializationExpression(
                Expression.Convert(projection.Projector, newType),
                info);

            return new ProjectionExpression(
                source,
                projector);
        }
        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);
        }
 public Expression Bind(ProjectionExpression projection, ProjectionBindingContext context, MethodCallExpression node, IEnumerable<Expression> arguments)
 {
     return new ProjectionExpression(
         new SkipExpression(
             projection.Source,
             (int)((ConstantExpression)arguments.Single()).Value),
         projection.Projector,
         projection.Aggregator);
 }
        public Expression Bind(ProjectionExpression projection, ProjectionBindingContext context, MethodCallExpression node, IEnumerable<Expression> arguments)
        {
            var distinct = new DistinctExpression(projection.Source, projection.Projector);

            var serializer = SerializerBuilder.Build(projection.Projector, context.SerializerRegistry);
            var info = new BsonSerializationInfo("_id", serializer, serializer.ValueType);
            var projector = new SerializationExpression(projection.Projector, info);

            return new ProjectionExpression(
                distinct,
                projector);
        }
        public Expression Bind(ProjectionExpression projection, ProjectionBindingContext context, MethodCallExpression node, IEnumerable<Expression> arguments)
        {
            var id = BindId(projection, context, arguments.First());
            var selector = BindSelector(projection, context, id, arguments.Last());

            var projector = BuildProjector(selector, context);

            return new ProjectionExpression(
                new GroupByWithResultSelectorExpression(
                    projection.Source,
                    selector),
                projector);
        }
        protected static Expression BindPredicate(ProjectionExpression projection, ProjectionBindingContext context, Expression source, Expression argument)
        {
            // this is actually a predicate that needs to be rendered as a WhereExpression
            var lambda = ExtensionExpressionVisitor.GetLambda(argument);
            var binder = new AccumulatorBinder(context.GroupMap, context.SerializerRegistry);
            binder.RegisterParameterReplacement(lambda.Parameters[0], projection.Projector);
            var predicate = binder.Bind(lambda.Body);

            source = new WhereExpression(
                source,
                predicate);

            return source;
        }
        public Expression Bind(ProjectionExpression projection, ProjectionBindingContext context, MethodCallExpression node, IEnumerable<Expression> arguments)
        {
            var collectionLambda = ExtensionExpressionVisitor.GetLambda(arguments.First());
            var binder = new AccumulatorBinder(context.GroupMap, context.SerializerRegistry);
            binder.RegisterParameterReplacement(collectionLambda.Parameters[0], projection.Projector);

            var collectionSelector = binder.Bind(collectionLambda.Body) as SerializationExpression;
            if (collectionSelector == null)
            {
                var message = string.Format("Unable to determine the collection selector in the tree: {0}", node.ToString());
                throw new NotSupportedException(message);
            }
            var collectionArraySerializer = collectionSelector.SerializationInfo.Serializer as IBsonArraySerializer;
            BsonSerializationInfo collectionItemSerializationInfo;
            if (collectionArraySerializer == null || !collectionArraySerializer.TryGetItemSerializationInfo(out collectionItemSerializationInfo))
            {
                var message = string.Format("The collection selector's serializer must implement IBsonArraySerializer: {0}", node.ToString());
                throw new NotSupportedException(message);
            }

            Expression resultSelector;
            if (arguments.Count() == 2)
            {
                var resultLambda = ExtensionExpressionVisitor.GetLambda(arguments.Last());

                binder.RegisterParameterReplacement(resultLambda.Parameters[0], projection.Projector);
                binder.RegisterParameterReplacement(
                    resultLambda.Parameters[1],
                    new SerializationExpression(
                        resultLambda.Parameters[1],
                        collectionItemSerializationInfo.WithNewName(collectionSelector.SerializationInfo.ElementName)));

                resultSelector = binder.Bind(resultLambda.Body);
            }
            else
            {
                resultSelector = new SerializationExpression(
                    collectionSelector,
                    collectionItemSerializationInfo.WithNewName(collectionSelector.SerializationInfo.ElementName));
            }

            var projector = BuildProjector(resultSelector, context);

            return new ProjectionExpression(
                new SelectManyExpression(
                    projection.Source,
                    collectionSelector,
                    resultSelector),
                projector);
        }
        public Expression Bind(ProjectionExpression projection, ProjectionBindingContext context, MethodCallExpression node, IEnumerable<Expression> arguments)
        {
            var lambda = ExtensionExpressionVisitor.GetLambda(arguments.Single());
            var binder = new AccumulatorBinder(context.GroupMap, context.SerializerRegistry);
            binder.RegisterParameterReplacement(lambda.Parameters[0], projection.Projector);

            var predicate = binder.Bind(lambda.Body);

            return new ProjectionExpression(
                new WhereExpression(
                    projection.Source,
                    predicate),
                projection.Projector,
                projection.Aggregator);
        }
        public Expression Bind(ProjectionExpression projection, ProjectionBindingContext context, MethodCallExpression node, IEnumerable<Expression> arguments)
        {
            List<KeyValuePair<Registration, IMethodCallBinder>> namedBinders;
            if (!_binders.TryGetValue(node.Method.Name, out namedBinders))
            {
                return null;
            }

            var binder = namedBinders.Where(x => x.Key.Filter(node)).Select(x => x.Value).FirstOrDefault();
            if (binder == null)
            {
                return null;
            }

            return binder.Bind(projection, context, node, arguments);
        }
        private GroupIdExpression BindId(ProjectionExpression projection, ProjectionBindingContext context, Expression node)
        {
            var lambda = ExtensionExpressionVisitor.GetLambda(node);
            var binder = new AccumulatorBinder(context.GroupMap, context.SerializerRegistry);
            binder.RegisterParameterReplacement(lambda.Parameters[0], projection.Projector);
            var selector = binder.Bind(lambda.Body);

            if (!(selector is ISerializationExpression))
            {
                var serializer = SerializerBuilder.Build(selector, context.SerializerRegistry);
                selector = new SerializationExpression(
                    selector,
                    new BsonSerializationInfo(null, serializer, serializer.ValueType));
            }

            return new GroupIdExpression(selector, ((ISerializationExpression)selector).SerializationInfo);
        }
        public override Expression Bind(ProjectionExpression projection, ProjectionBindingContext context, MethodCallExpression node, IEnumerable<Expression> arguments)
        {
            var aggregator = CreateAggregator(node.Method.Name, projection.Projector.Type);

            var source = projection.Source;
            var argument = arguments.FirstOrDefault();
            if (argument != null && ExtensionExpressionVisitor.IsLambda(argument))
            {
                source = BindPredicate(projection, context, source, argument);
            }

            source = new TakeExpression(source, 2);

            return new ProjectionExpression(
                source,
                projection.Projector,
                aggregator);
        }
        protected internal override Expression VisitProjection(ProjectionExpression node)
        {
            var model = QueryableExecutionModelBuilder.Build(node, _serializerRegistry);

            Expression executor;
            if (_cancellationToken != null)
            {
                // we are async
                executor = Expression.Call(
                    _provider,
                    "ExecuteAsync",
                    Type.EmptyTypes,
                    Expression.Constant(model, typeof(QueryableExecutionModel)),
                    _cancellationToken);

                if (node.Aggregator != null)
                {
                    executor = Expression.Invoke(
                        node.Aggregator,
                        Expression.Convert(executor, node.Aggregator.Parameters[0].Type),
                        _cancellationToken);
                }
            }
            else
            {
                // we are sync
                executor = Expression.Call(
                    _provider,
                    "Execute",
                    Type.EmptyTypes,
                    Expression.Constant(model, typeof(QueryableExecutionModel)));

                if (node.Aggregator != null)
                {
                    executor = Expression.Invoke(
                        node.Aggregator,
                        Expression.Convert(executor, node.Aggregator.Parameters[0].Type));
                }
            }

            return executor;
        }
        public Expression Bind(ProjectionExpression projection, ProjectionBindingContext context, MethodCallExpression node, IEnumerable<Expression> arguments)
        {
            var source = projection.Source;
            var sortClauses = GatherPreviousSortClauses(projection.Source, out source);

            var lambda = ExtensionExpressionVisitor.GetLambda(arguments.Single());
            var binder = new AccumulatorBinder(context.GroupMap, context.SerializerRegistry);
            binder.RegisterParameterReplacement(lambda.Parameters[0], projection.Projector);

            var direction = GetDirection(node.Method.Name);
            var ordering = binder.Bind(lambda.Body);

            sortClauses.Add(new SortClause(ordering, direction));

            return new ProjectionExpression(
                new OrderByExpression(
                    source,
                    sortClauses),
                projection.Projector,
                projection.Aggregator);
        }
        public Expression Bind(ProjectionExpression projection, ProjectionBindingContext context, MethodCallExpression node, IEnumerable<Expression> arguments)
        {
            var lambda = ExtensionExpressionVisitor.GetLambda(arguments.Single());
            if (lambda.Body == lambda.Parameters[0])
            {
                // we can ignore identity projections
                return projection;
            }

            var binder = new AccumulatorBinder(context.GroupMap, context.SerializerRegistry);
            binder.RegisterParameterReplacement(lambda.Parameters[0], projection.Projector);

            var selector = binder.Bind(lambda.Body);
            var projector = BuildProjector(selector, context);

            return new ProjectionExpression(
                new SelectExpression(
                    projection.Source,
                    selector),
                projector);
        }
        private Expression BindSelector(ProjectionExpression projection, ProjectionBindingContext context, Expression id, Expression node)
        {
            var lambda = ExtensionExpressionVisitor.GetLambda(node);
            var binder = new AccumulatorBinder(context.GroupMap, context.SerializerRegistry);

            var serializer = SerializerBuilder.Build(projection.Projector, context.SerializerRegistry);
            var sequenceSerializer = (IBsonSerializer)Activator.CreateInstance(
                typeof(ArraySerializer<>).MakeGenericType(projection.Projector.Type),
                new object[] { serializer });
            var sequenceInfo = new BsonSerializationInfo(
                null,
                sequenceSerializer,
                sequenceSerializer.ValueType);
            var sequenceExpression = new SerializationExpression(
                lambda.Parameters[1],
                sequenceInfo);

            binder.RegisterParameterReplacement(lambda.Parameters[0], id);
            binder.RegisterParameterReplacement(lambda.Parameters[1], sequenceExpression);
            var correlationId = Guid.NewGuid();
            context.GroupMap.Add(sequenceExpression, correlationId);
            var bound = binder.Bind(lambda.Body);
            return CorrelatedAccumulatorRemover.Remove(bound, correlationId);
        }
        private void VisitProjection(ProjectionExpression node)
        {
            Visit(node.Source);

            var serializationExpression = node.Projector as ISerializationExpression;
            if (serializationExpression != null)
            {
                var info = serializationExpression.SerializationInfo;
                if (info.ElementName != null)
                {
                    // We are projecting a field, however the server only responds
                    // with documents. So we'll create a projector that reads a document
                    // and then projects the field out of it.
                    var parameter = Expression.Parameter(typeof(ProjectedObject), "document");
                    var projector = Expression.Lambda(
                        Expression.Call(
                            parameter,
                            "GetValue",
                            new Type[] { info.Serializer.ValueType },
                            Expression.Constant(info.ElementName),
                            Expression.Constant(info.Serializer.ValueType.GetDefaultValue(), typeof(object))),
                        parameter);
                    var innerSerializer = new ProjectedObjectDeserializer(new[] { info });
                    _serializer = (IBsonSerializer)Activator.CreateInstance(
                        typeof(ProjectingDeserializer<,>).MakeGenericType(typeof(ProjectedObject), info.Serializer.ValueType),
                        new object[] 
                            { 
                                innerSerializer,
                                projector.Compile()
                            });
                    return;
                }
            }

            _serializer = SerializerBuilder.Build(node.Projector, _serializerRegistry);
        }
        protected internal override Expression VisitProjection(ProjectionExpression node)
        {
            _lookup = AccumulatorGatherer.Gather(node.Source).ToLookup(x => x.CorrelationId);

            return base.VisitProjection(node);
        }
 public abstract Expression Bind(ProjectionExpression projection, ProjectionBindingContext context, MethodCallExpression node, IEnumerable<Expression> arguments);
 protected internal virtual Expression VisitProjection(ProjectionExpression node)
 {
     return node.Update(
         Visit(node.Source),
         Visit(node.Projector),
         VisitAndConvert<LambdaExpression>(node.Aggregator, "VisitPipeline"));
 }