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); }
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)); }
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; }
protected internal override ResultOperator Update(ExtensionExpressionVisitor visitor) { var value = visitor.Visit(_value); if (value != _value) { return(new ContainsResultOperator(value)); } return(this); }
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); }
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; }
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 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 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)); }
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)); }
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]))); }
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)); }
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)); }