private bool TryBuildMap(MethodCallExpression node, out BsonValue result)
        {
            result = null;
            var sourceSerializationExpression = node.Arguments[0] as ISerializationExpression;

            if (sourceSerializationExpression != null)
            {
                var lambda = ExtensionExpressionVisitor.GetLambda(node.Arguments[1]);
                if (lambda.Body is ISerializationExpression)
                {
                    result = BuildValue(lambda.Body);
                    return(true);
                }

                var inputValue = BuildValue(node.Arguments[0]);
                var asValue    = lambda.Parameters[0].Name;

                // HACK: need to add a leading $ sign to the replacement because of how we resolve values.
                var body    = FieldNameReplacer.Replace(lambda.Body, sourceSerializationExpression.SerializationInfo.ElementName, "$" + asValue);
                var inValue = BuildValue(body);

                result = new BsonDocument("$map", new BsonDocument
                {
                    { "input", inputValue },
                    { "as", asValue },
                    { "in", inValue }
                });
                return(true);
            }

            return(false);
        }
Esempio n. 2
0
        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));
        }
Esempio n. 3
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));
        }
        static ProjectionBinder()
        {
            var nameBasedBinder = new NameBasedMethodCallBinder();

            nameBasedBinder.Register(new AnyBinder(), "Any", "AnyAsync");

            nameBasedBinder.Register(new AverageBinder(), "Average", "AverageAsync");

            nameBasedBinder.Register(new CountBinder(), "Count", "CountAsync", "LongCount", "LongCountAsync");

            nameBasedBinder.Register(new DistinctBinder(), node => node.Arguments.Count == 1, "Distinct");

            nameBasedBinder.Register(new FirstBinder(), "First", "FirstAsync", "FirstOrDefault", "FirstOrDefaultAsync");

            nameBasedBinder.Register(new CorrelatedGroupByBinder(), node =>
                                     node.Arguments.Count == 2 &&
                                     ExtensionExpressionVisitor.IsLambda(node.Arguments[1], 1),
                                     "GroupBy");

            nameBasedBinder.Register(new GroupByWithResultSelectorBinder(), node =>
                                     node.Arguments.Count == 3 &&
                                     ExtensionExpressionVisitor.IsLambda(node.Arguments[1], 1) &&
                                     ExtensionExpressionVisitor.IsLambda(node.Arguments[2], 2),
                                     "GroupBy");

            nameBasedBinder.Register(new MaxBinder(), "Max", "MaxAsync");

            nameBasedBinder.Register(new MinBinder(), "Min", "MinAsync");

            nameBasedBinder.Register(new OfTypeBinder(), "OfType");

            nameBasedBinder.Register(new OrderByBinder(), node =>
                                     node.Arguments.Count == 2 &&
                                     ExtensionExpressionVisitor.IsLambda(node.Arguments[1], 1),
                                     "OrderBy", "OrderByDescending", "ThenBy", "ThenByDescending");

            nameBasedBinder.Register(new SelectBinder(), node =>
                                     node.Arguments.Count == 2 &&
                                     ExtensionExpressionVisitor.IsLambda(node.Arguments[1], 1),
                                     "Select");

            nameBasedBinder.Register(new SingleBinder(), "Single", "SingleAsync", "SingleOrDefault", "SingleOrDefaultAsync");

            nameBasedBinder.Register(new SkipBinder(), "Skip");

            nameBasedBinder.Register(new TakeBinder(), "Take");

            nameBasedBinder.Register(new SumBinder(), "Sum", "SumAsync");

            nameBasedBinder.Register(new WhereBinder(), node =>
                                     node.Arguments.Count == 2 &&
                                     ExtensionExpressionVisitor.IsLambda(node.Arguments[1], 1),
                                     "Where");

            __methodCallBinder = nameBasedBinder;
        }
        protected internal override ResultOperator Update(ExtensionExpressionVisitor visitor)
        {
            var value = visitor.Visit(_value);
            if (value != _value)
            {
                return new ContainsResultOperator(value);
            }

            return this;
        }
Esempio n. 6
0
        protected internal override ResultOperator Update(ExtensionExpressionVisitor visitor)
        {
            var value = visitor.Visit(_value);

            if (value != _value)
            {
                return(new ContainsResultOperator(value));
            }

            return(this);
        }
Esempio n. 7
0
        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));
        }
        private BsonValue BuildMethodCall(MethodCallExpression node)
        {
            BsonValue result;

            if (ExtensionExpressionVisitor.IsLinqMethod(node) && TryBuildLinqMethodCall(node, out result))
            {
                return(result);
            }

            if (node.Object == null &&
                node.Method.DeclaringType == typeof(string) &&
                TryBuildStaticStringMethodCall(node, out result))
            {
                return(result);
            }

            if (node.Object != null &&
                node.Object.Type == typeof(string) &&
                TryBuildStringMethodCall(node, out result))
            {
                return(result);
            }

            if (node.Object != null &&
                node.Object.Type.IsGenericType &&
                node.Object.Type.GetGenericTypeDefinition() == typeof(HashSet <>) &&
                TryBuildHashSetMethodCall(node, out result))
            {
                return(result);
            }

            if (node.Object != null &&
                node.Method.Name == "CompareTo" &&
                (node.Object.Type.ImplementsInterface(typeof(IComparable <>)) ||
                 node.Object.Type.ImplementsInterface(typeof(IComparable))))
            {
                return(new BsonDocument("$cmp", new BsonArray(new[] { BuildValue(node.Object), BuildValue(node.Arguments[0]) })));
            }

            if (node.Object != null &&
                node.Method.Name == "Equals" &&
                node.Arguments.Count == 1)
            {
                return(new BsonDocument("$eq", new BsonArray(new[] { BuildValue(node.Object), BuildValue(node.Arguments[0]) })));
            }

            var message = string.Format("{0} of type {1} is not supported in the expression tree {2}.",
                                        node.Method.Name,
                                        node.Method.DeclaringType,
                                        node.ToString());

            throw new NotSupportedException(message);
        }
Esempio n. 9
0
        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);
        }
        protected internal override ResultOperator Update(ExtensionExpressionVisitor visitor)
        {
            var seed = visitor.Visit(_seed);
            var reducer = visitor.Visit(_reducer);
            Expression finalizer = null;
            if (_finalizer != null)
            {
                finalizer = visitor.Visit(_finalizer);
            }
            if (seed != _seed || reducer != _reducer || finalizer != _finalizer)
            {
                return new AggregateResultOperator(seed, reducer, finalizer, _itemName, _serializer);
            }

            return this;
        }
Esempio n. 11
0
        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));
        }
Esempio n. 12
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. 13
0
        protected internal override ResultOperator Update(ExtensionExpressionVisitor visitor)
        {
            var        seed      = visitor.Visit(_seed);
            var        reducer   = visitor.Visit(_reducer);
            Expression finalizer = null;

            if (_finalizer != null)
            {
                finalizer = visitor.Visit(_finalizer);
            }
            if (seed != _seed || reducer != _reducer || finalizer != _finalizer)
            {
                return(new AggregateResultOperator(seed, reducer, finalizer, _itemName, _serializer));
            }

            return(this);
        }
        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));
        }
Esempio n. 15
0
        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));
        }
Esempio n. 16
0
        public Expression Transform(MethodCallExpression node)
        {
            if (!ExtensionExpressionVisitor.IsLinqMethod(node, "Select") ||
                !ExtensionExpressionVisitor.IsLambda(node.Arguments[1], 1))
            {
                return(node);
            }

            var call = node.Arguments[0] as MethodCallExpression;

            // we are going to rewrite g.Last().Member to g.Select(x => x.Member).Last()
            if (call == null ||
                !ExtensionExpressionVisitor.IsLinqMethod(call, "Select") ||
                !ExtensionExpressionVisitor.IsLambda(call.Arguments[1], 1))
            {
                return(node);
            }

            var innerLambda = ExtensionExpressionVisitor.GetLambda(call.Arguments[1]);
            var outerLambda = ExtensionExpressionVisitor.GetLambda(node.Arguments[1]);

            var sourceType = innerLambda.Parameters[0].Type;
            var resultType = outerLambda.Body.Type;

            var innerSelector = innerLambda.Body;
            var outerSelector = outerLambda.Body;

            var selector = ParameterReplacer.Replace(outerSelector, outerLambda.Parameters[0], innerSelector);

            return(Expression.Call(
                       typeof(Enumerable),
                       "Select",
                       new[] { sourceType, resultType },
                       call.Arguments[0],
                       Expression.Lambda(
                           typeof(Func <,>).MakeGenericType(sourceType, resultType),
                           selector,
                           innerLambda.Parameters[0])));
        }
Esempio n. 17
0
        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));
        }
Esempio n. 18
0
        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));
        }
Esempio n. 19
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));
        }