// 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);
        }
Esempio n. 9
0
        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);
        }
Esempio n. 11
0
        // 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);
        }
Esempio n. 12
0
        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);
        }
Esempio n. 13
0
        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));
            }
        }