// public static methods public static AstPipeline Translate(TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.Is(QueryableMethod.Select)) { var sourceExpression = arguments[0]; var pipeline = ExpressionToPipelineTranslator.Translate(context, sourceExpression); var sourceSerializer = pipeline.OutputSerializer; var selectorLambda = ExpressionHelper.UnquoteLambda(arguments[1]); if (selectorLambda.Body == selectorLambda.Parameters[0]) { return(pipeline); // ignore identity projection: Select(x => x) } var selectorTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, selectorLambda, sourceSerializer, asRoot: true); var(projectStage, projectionSerializer) = ProjectionHelper.CreateProjectStage(selectorTranslation); pipeline = pipeline.AddStages(projectionSerializer, projectStage); return(pipeline); } throw new ExpressionNotSupportedException(expression); }
// public static methods public static AstPipeline Translate(TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.IsOneOf(__groupByMethods)) { var sourceExpression = arguments[0]; var pipeline = ExpressionToPipelineTranslator.Translate(context, sourceExpression); var sourceSerializer = pipeline.OutputSerializer; var keySelectorLambda = ExpressionHelper.UnquoteLambda(arguments[1]); var keySelectorTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, keySelectorLambda, sourceSerializer, asRoot: true); var keySerializer = keySelectorTranslation.Serializer; var(elementAst, elementSerializer) = TranslateElement(context, method, arguments, sourceSerializer); var groupingSerializer = IGroupingSerializer.Create(keySerializer, elementSerializer); pipeline = pipeline.AddStages( groupingSerializer, AstStage.Group( id: keySelectorTranslation.Ast, fields: AstExpression.AccumulatorField("_elements", AstAccumulatorOperator.Push, elementAst))); if (method.IsOneOf(__groupByWithResultSelectorMethods)) { pipeline = TranslateResultSelector(context, pipeline, arguments, keySerializer, elementSerializer); } return(pipeline); } throw new ExpressionNotSupportedException(expression); }
private static (AstExpression, IBsonSerializer) TranslateElement( TranslationContext context, MethodInfo method, ReadOnlyCollection <Expression> arguments, IBsonSerializer sourceSerializer) { AstExpression elementAst; IBsonSerializer elementSerializer; if (method.IsOneOf(__groupByWithElementSelectorMethods)) { var elementLambda = ExpressionHelper.UnquoteLambda(arguments[2]); var elementTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, elementLambda, sourceSerializer, asRoot: true); elementAst = elementTranslation.Ast; elementSerializer = elementTranslation.Serializer; } else { var rootVar = AstExpression.Var("ROOT", isCurrent: true); if (sourceSerializer is IWrappedValueSerializer wrappedSerializer) { elementAst = AstExpression.GetField(rootVar, wrappedSerializer.FieldName); elementSerializer = wrappedSerializer.ValueSerializer; } else { elementAst = rootVar; elementSerializer = sourceSerializer; } } return(elementAst, elementSerializer); }
public static AggregationExpression Translate(TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.IsOneOf(EnumerableMethod.First, EnumerableMethod.FirstWithPredicate, EnumerableMethod.Last, EnumerableMethod.LastWithPredicate)) { var sourceExpression = arguments[0]; var sourceTranslation = ExpressionToAggregationExpressionTranslator.TranslateEnumerable(context, sourceExpression); var array = sourceTranslation.Ast; var itemSerializer = ArraySerializerHelper.GetItemSerializer(sourceTranslation.Serializer); if (method.IsOneOf(EnumerableMethod.FirstWithPredicate, EnumerableMethod.LastWithPredicate)) { var predicateLambda = (LambdaExpression)arguments[1]; var predicateTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, predicateLambda, itemSerializer, asRoot: false); var predicateParameter = predicateLambda.Parameters[0]; array = AstExpression.Filter( input: array, cond: predicateTranslation.Ast, @as: predicateParameter.Name); } var ast = method.Name == "First" ? AstExpression.First(array) : AstExpression.Last(array); return(new AggregationExpression(expression, ast, itemSerializer)); } if (WindowMethodToAggregationExpressionTranslator.CanTranslate(expression)) { return(WindowMethodToAggregationExpressionTranslator.Translate(context, expression)); } throw new ExpressionNotSupportedException(expression); }
// public static methods public static ExecutableQuery <TDocument, TOutput> Translate <TDocument>(MongoQueryProvider <TDocument> provider, TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.IsOneOf(__averageMethods)) { var sourceExpression = arguments[0]; var pipeline = ExpressionToPipelineTranslator.Translate(context, sourceExpression); var sourceSerializer = pipeline.OutputSerializer; AstExpression valueExpression; if (method.IsOneOf(__averageWithSelectorMethods)) { var selectorLambda = ExpressionHelper.UnquoteLambda(arguments[1]); var selectorTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, selectorLambda, sourceSerializer, asRoot: true); valueExpression = selectorTranslation.Ast; } else { Ensure.That(sourceSerializer is IWrappedValueSerializer, "Expected sourceSerializer to be an IWrappedValueSerializer.", nameof(sourceSerializer)); var root = AstExpression.Var("ROOT", isCurrent: true); valueExpression = AstExpression.GetField(root, "_v"); } IBsonSerializer outputValueSerializer = expression.GetResultType() switch { Type t when t == typeof(int) => new Int32Serializer(), Type t when t == typeof(long) => new Int64Serializer(), Type t when t == typeof(float) => new SingleSerializer(), Type t when t == typeof(double) => new DoubleSerializer(), Type t when t == typeof(decimal) => new DecimalSerializer(), Type { IsConstructedGenericType : true } t when t.GetGenericTypeDefinition() == typeof(Nullable <>) => (IBsonSerializer)Activator.CreateInstance(typeof(NullableSerializer <>).MakeGenericType(t.GenericTypeArguments[0])), _ => throw new ExpressionNotSupportedException(expression) }; var outputWrappedValueSerializer = WrappedValueSerializer.Create("_v", outputValueSerializer); pipeline = pipeline.AddStages( outputWrappedValueSerializer, AstStage.Group( id: BsonNull.Value, fields: AstExpression.AccumulatorField("_v", AstAccumulatorOperator.Avg, valueExpression)), AstStage.Project(AstProject.ExcludeId())); return(ExecutableQuery.Create( provider.Collection, provider.Options, pipeline, __finalizer)); } throw new ExpressionNotSupportedException(expression); } }
internal override BsonValue TranslateExpressionToAggregateExpression <TSource, TResult>( Expression <Func <TSource, TResult> > expression, IBsonSerializer <TSource> sourceSerializer, IBsonSerializerRegistry serializerRegistry, ExpressionTranslationOptions translationOptions) { expression = (Expression <Func <TSource, TResult> >)PartialEvaluator.EvaluatePartially(expression); var context = TranslationContext.Create(expression, sourceSerializer); var translation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, expression, sourceSerializer, asRoot: true); var simplifiedAst = AstSimplifier.Simplify(translation.Ast); return(simplifiedAst.Render()); }
// public static methods public static ExecutableQuery <TDocument, TOutput> Translate <TDocument>(MongoQueryProvider <TDocument> provider, TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.IsOneOf(__maxMethods)) { var sourceExpression = arguments[0]; var pipeline = ExpressionToPipelineTranslator.Translate(context, sourceExpression); var sourceSerializer = pipeline.OutputSerializer; var root = AstExpression.Var("ROOT", isCurrent: true); AstExpression valueAst; IBsonSerializer valueSerializer; if (method.IsOneOf(__maxWithSelectorMethods)) { var selectorLambda = ExpressionHelper.UnquoteLambda(arguments[1]); var selectorTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, selectorLambda, sourceSerializer, asRoot: true); if (selectorTranslation.Serializer is IBsonDocumentSerializer) { valueAst = selectorTranslation.Ast; valueSerializer = selectorTranslation.Serializer; } else { valueAst = AstExpression.ComputedDocument(new[] { AstExpression.ComputedField("_v", selectorTranslation.Ast) }); valueSerializer = WrappedValueSerializer.Create("_v", selectorTranslation.Serializer); } } else { valueAst = root; valueSerializer = pipeline.OutputSerializer; } pipeline = pipeline.AddStages( valueSerializer, AstStage.Group( id: BsonNull.Value, fields: AstExpression.AccumulatorField("_max", AstAccumulatorOperator.Max, valueAst)), AstStage.ReplaceRoot(AstExpression.GetField(root, "_max"))); return(ExecutableQuery.Create( provider.Collection, provider.Options, pipeline, __finalizer)); } throw new ExpressionNotSupportedException(expression); }
public static AggregationExpression Translate(TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.IsOneOf(__countMethods)) { var sourceExpression = arguments[0]; var sourceTranslation = ExpressionToAggregationExpressionTranslator.TranslateEnumerable(context, sourceExpression); AstExpression ast; if (method.IsOneOf(__countWithPredicateMethods)) { if (sourceExpression.Type == typeof(string)) { throw new ExpressionNotSupportedException(expression); } var predicateLambda = (LambdaExpression)arguments[1]; var sourceItemSerializer = ArraySerializerHelper.GetItemSerializer(sourceTranslation.Serializer); var predicateTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, predicateLambda, sourceItemSerializer, asRoot: false); var filteredSourceAst = AstExpression.Filter( input: sourceTranslation.Ast, cond: predicateTranslation.Ast, @as: predicateLambda.Parameters[0].Name); ast = AstExpression.Size(filteredSourceAst); } else { if (sourceExpression.Type == typeof(string)) { ast = AstExpression.StrLenCP(sourceTranslation.Ast); } else { ast = AstExpression.Size(sourceTranslation.Ast); } } var serializer = GetSerializer(expression.Type); return(new AggregationExpression(expression, ast, serializer)); } if (WindowMethodToAggregationExpressionTranslator.CanTranslate(expression)) { return(WindowMethodToAggregationExpressionTranslator.Translate(context, expression)); } throw new ExpressionNotSupportedException(expression); }
public static string GetFieldPath(this LambdaExpression fieldSelectorLambda, TranslationContext context, IBsonSerializer parameterSerializer) { var fieldSelectorTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, fieldSelectorLambda, parameterSerializer, asRoot: true); if (fieldSelectorTranslation.Ast.CanBeConvertedToFieldPath()) { var path = fieldSelectorTranslation.Ast.ConvertToFieldPath(); if (path.Length >= 2 && path[0] == '$' && path[1] != '$') { return(path.Substring(1)); } } throw new ExpressionNotSupportedException(fieldSelectorLambda); }
// public static methods public static ExecutableQuery <TDocument, TOutput> Translate <TDocument>(MongoQueryProvider <TDocument> provider, TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.IsOneOf(__standardDeviationMethods)) { var sourceExpression = ConvertHelper.RemoveConvertToMongoQueryable(arguments[0]); var pipeline = ExpressionToPipelineTranslator.Translate(context, sourceExpression); var sourceSerializer = pipeline.OutputSerializer; var stdDevOperator = method.IsOneOf(__standardDeviationPopulationMethods) ? AstAccumulatorOperator.StdDevPop : AstAccumulatorOperator.StdDevSamp; AstExpression valueAst; if (method.IsOneOf(__standardDeviationWithSelectorMethods)) { var selectorLambda = ExpressionHelper.UnquoteLambda(arguments[1]); var selectorTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, selectorLambda, sourceSerializer, asRoot: true); valueAst = selectorTranslation.Ast; } else { var root = AstExpression.Var("ROOT", isCurrent: true); valueAst = AstExpression.GetField(root, "_v"); } var outputValueType = expression.GetResultType(); var outputValueSerializer = BsonSerializer.LookupSerializer(outputValueType); var outputWrappedValueSerializer = WrappedValueSerializer.Create("_v", outputValueSerializer); pipeline = pipeline.AddStages( outputWrappedValueSerializer, AstStage.Group( id: BsonNull.Value, AstExpression.AccumulatorField("_v", stdDevOperator, valueAst)), AstStage.Project(AstProject.ExcludeId())); var finalizer = method.IsOneOf(__standardDeviationNullableMethods) ? __singleOrDefaultFinalizer : __singleFinalizer; return(ExecutableQuery.Create( provider.Collection, provider.Options, pipeline, finalizer)); } throw new ExpressionNotSupportedException(expression); }
// public static methods public static ExecutableQuery <TDocument, TOutput> Translate <TDocument>(MongoQueryProvider <TDocument> provider, TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.IsOneOf(__sumMethods)) { var sourceExpression = arguments[0]; var pipeline = ExpressionToPipelineTranslator.Translate(context, sourceExpression); var sourceSerializer = pipeline.OutputSerializer; AstExpression valueAst; if (method.IsOneOf(__sumWithSelectorMethods)) { var selectorLambda = ExpressionHelper.UnquoteLambda(arguments[1]); var selectorTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, selectorLambda, sourceSerializer, asRoot: true); valueAst = selectorTranslation.Ast; } else { Ensure.That(sourceSerializer is IWrappedValueSerializer, "Expected sourceSerializer to be an IWrappedValueSerializer.", nameof(sourceSerializer)); var rootVar = AstExpression.Var("ROOT", isCurrent: true); valueAst = AstExpression.GetField(rootVar, "_v"); } var outputValueType = expression.GetResultType(); var outputValueSerializer = BsonSerializer.LookupSerializer(outputValueType); var outputWrappedValueSerializer = WrappedValueSerializer.Create("_v", outputValueSerializer); pipeline = pipeline.AddStages( outputWrappedValueSerializer, AstStage.Group( id: BsonNull.Value, fields: AstExpression.AccumulatorField("_v", AstAccumulatorOperator.Sum, valueAst)), AstStage.Project(AstProject.ExcludeId())); return(ExecutableQuery.Create( provider.Collection, provider.Options, pipeline, __finalizer)); } throw new ExpressionNotSupportedException(expression); }
private static AstPipeline TranslateSelectMany( TranslationContext context, AstPipeline pipeline, ReadOnlyCollection <Expression> arguments) { var sourceSerializer = pipeline.OutputSerializer; var selectorLambda = ExpressionHelper.UnquoteLambda(arguments[1]); var selectorTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, selectorLambda, sourceSerializer, asRoot: true); var resultValueSerializer = ArraySerializerHelper.GetItemSerializer(selectorTranslation.Serializer); var resultWrappedValueSerializer = WrappedValueSerializer.Create("_v", resultValueSerializer); pipeline = pipeline.AddStages( resultWrappedValueSerializer, AstStage.Project( AstProject.Set("_v", selectorTranslation.Ast), AstProject.ExcludeId()), AstStage.Unwind("_v")); return(pipeline); }
private static AstPipeline TranslateSelectManyWithCollectionSelectorAndResultSelector( TranslationContext context, AstPipeline pipeline, ReadOnlyCollection <Expression> arguments) { var sourceSerializer = pipeline.OutputSerializer; var collectionSelectorLambda = ExpressionHelper.UnquoteLambda(arguments[1]); var collectionSelectorTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, collectionSelectorLambda, sourceSerializer, asRoot: true); var resultSelectorLambda = ExpressionHelper.UnquoteLambda(arguments[2]); if (resultSelectorLambda.Body == resultSelectorLambda.Parameters[1]) { // special case identity resultSelector: (x, y) => y return(TranslateSelectManyWithCollectionSelectorAndIdentityResultSelector(pipeline, collectionSelectorTranslation)); } else { return(TranslateSelectManyWithCollectionSelectorAndNonIdentityResultSelector(context, pipeline, collectionSelectorTranslation, resultSelectorLambda)); } }