public static AggregationExpression Translate(TranslationContext context, MethodCallExpression expression)
        {
            var method    = expression.Method;
            var arguments = expression.Arguments;

            if (method.Is(EnumerableMethod.Select))
            {
                var sourceExpression            = arguments[0];
                var sourceTranslation           = ExpressionToAggregationExpressionTranslator.TranslateEnumerable(context, sourceExpression);
                var selectorLambda              = (LambdaExpression)arguments[1];
                var selectorParameter           = selectorLambda.Parameters[0];
                var selectorParameterSerializer = ArraySerializerHelper.GetItemSerializer(sourceTranslation.Serializer);
                var selectorParameterSymbol     = context.CreateSymbol(selectorParameter, selectorParameterSerializer);
                var selectorContext             = context.WithSymbol(selectorParameterSymbol);
                var translatedSelector          = ExpressionToAggregationExpressionTranslator.Translate(selectorContext, selectorLambda.Body);
                var ast = AstExpression.Map(
                    sourceTranslation.Ast,
                    selectorParameterSymbol.Var,
                    translatedSelector.Ast);
                var serializer = IEnumerableSerializer.Create(translatedSelector.Serializer);
                return(new AggregationExpression(expression, ast, serializer));
            }

            throw new ExpressionNotSupportedException(expression);
        }
        public static AggregationExpression Translate(TranslationContext context, MethodCallExpression expression)
        {
            var method    = expression.Method;
            var arguments = expression.Arguments;

            if (method.Is(EnumerableMethod.Zip))
            {
                var firstExpression           = arguments[0];
                var firstTranslation          = ExpressionToAggregationExpressionTranslator.Translate(context, firstExpression);
                var secondExpression          = arguments[1];
                var secondTranslation         = ExpressionToAggregationExpressionTranslator.Translate(context, secondExpression);
                var resultSelectorLambda      = (LambdaExpression)arguments[2];
                var resultSelectorParameters  = resultSelectorLambda.Parameters;
                var resultSelectorParameter1  = resultSelectorParameters[0];
                var resultSelectorParameter2  = resultSelectorParameters[1];
                var resultSelectorSymbol1     = context.CreateSymbol(resultSelectorParameter1, BsonSerializer.LookupSerializer(resultSelectorParameter1.Type));
                var resultSelectorSymbol2     = context.CreateSymbol(resultSelectorParameter2, BsonSerializer.LookupSerializer(resultSelectorParameter2.Type));
                var resultSelectorContext     = context.WithSymbols(resultSelectorSymbol1, resultSelectorSymbol2);
                var resultSelectorTranslation = ExpressionToAggregationExpressionTranslator.Translate(resultSelectorContext, resultSelectorLambda.Body);
                var @as = AstExpression.Var("z__");
                var ast = AstExpression.Map(
                    input: AstExpression.Zip(new[] { firstTranslation.Ast, secondTranslation.Ast }),
                    @as: @as,
                    @in: AstExpression.Let(
                        AstExpression.VarBinding(resultSelectorSymbol1.Var, AstExpression.ArrayElemAt(@as, 0)),
                        AstExpression.VarBinding(resultSelectorSymbol2.Var, AstExpression.ArrayElemAt(@as, 1)),
                        @in: resultSelectorTranslation.Ast));
                var serializer = IEnumerableSerializer.Create(resultSelectorTranslation.Serializer);
                return(new AggregationExpression(expression, ast, serializer));
            }

            throw new ExpressionNotSupportedException(expression);
        }
Example #3
0
        // public static methods
        public static AstPipeline Translate(TranslationContext context, MethodCallExpression expression)
        {
            var method    = expression.Method;
            var arguments = expression.Arguments;

            if (method.Is(QueryableMethod.GroupJoin))
            {
                var outerExpression = arguments[0];
                var pipeline        = ExpressionToPipelineTranslator.Translate(context, outerExpression);
                var outerSerializer = pipeline.OutputSerializer;

                var wrapOuterStage = AstStage.Project(
                    AstProject.Set("_outer", AstExpression.Var("ROOT")),
                    AstProject.ExcludeId());
                var wrappedOuterSerializer = WrappedValueSerializer.Create("_outer", outerSerializer);

                var innerExpression = arguments[1];
                var(innerCollectionName, innerSerializer) = innerExpression.GetCollectionInfo(containerExpression: expression);

                var outerKeySelectorLambda = ExpressionHelper.UnquoteLambda(arguments[2]);
                var localFieldPath         = outerKeySelectorLambda.GetFieldPath(context, wrappedOuterSerializer);

                var innerKeySelectorLambda = ExpressionHelper.UnquoteLambda(arguments[3]);
                var foreignFieldPath       = innerKeySelectorLambda.GetFieldPath(context, innerSerializer);

                var lookupStage = AstStage.Lookup(
                    from: innerCollectionName,
                    match: new AstLookupStageEqualityMatch(localFieldPath, foreignFieldPath),
                    @as: "_inner");

                var resultSelectorLambda = ExpressionHelper.UnquoteLambda(arguments[4]);
                var root                       = AstExpression.Var("ROOT", isCurrent: true);
                var outerParameter             = resultSelectorLambda.Parameters[0];
                var outerField                 = AstExpression.GetField(root, "_outer");
                var outerSymbol                = context.CreateSymbol(outerParameter, outerField, outerSerializer);
                var innerParameter             = resultSelectorLambda.Parameters[1];
                var innerField                 = AstExpression.GetField(root, "_inner");
                var ienumerableInnerSerializer = IEnumerableSerializer.Create(innerSerializer);
                var innerSymbol                = context.CreateSymbol(innerParameter, innerField, ienumerableInnerSerializer);
                var resultSelectorContext      = context.WithSymbols(outerSymbol, innerSymbol);
                var resultSelectorTranslation  = ExpressionToAggregationExpressionTranslator.Translate(resultSelectorContext, resultSelectorLambda.Body);
                var(projectStage, newOutputSerializer) = ProjectionHelper.CreateProjectStage(resultSelectorTranslation);

                pipeline = pipeline.AddStages(
                    newOutputSerializer,
                    wrapOuterStage,
                    lookupStage,
                    projectStage);

                return(pipeline);
            }

            throw new ExpressionNotSupportedException(expression);
        }
Example #4
0
        public static AstFilterField TranslateEnumerable(TranslationContext context, Expression expression)
        {
            var field = Translate(context, expression);

            if (field.Serializer is IWrappedEnumerableSerializer wrappedEnumerableSerializer)
            {
                var enumerableSerializer = IEnumerableSerializer.Create(wrappedEnumerableSerializer.EnumerableElementSerializer);
                field = field.SubField(wrappedEnumerableSerializer.EnumerableFieldName, enumerableSerializer);
            }

            return(field);
        }
Example #5
0
        public static (AstFilterField, AstFilter) Translate(TranslationContext context, Expression sourceExpression)
        {
            if (sourceExpression is MethodCallExpression sourceMethodCallExpression)
            {
                var method    = sourceMethodCallExpression.Method;
                var arguments = sourceMethodCallExpression.Arguments;

                if (method.Is(EnumerableMethod.OfType))
                {
                    var ofTypeSourceExpression = arguments[0];
                    var(sourceField, sourceFilter) = Translate(context, ofTypeSourceExpression);

                    var nominalType                    = ArraySerializerHelper.GetItemSerializer(sourceField.Serializer).ValueType;
                    var actualType                     = method.GetGenericArguments()[0];
                    var discriminatorConvention        = BsonSerializer.LookupDiscriminatorConvention(actualType);
                    var discriminatorField             = AstFilter.Field(discriminatorConvention.ElementName, BsonValueSerializer.Instance);
                    var discriminatorValue             = discriminatorConvention.GetDiscriminator(nominalType, actualType);
                    var ofTypeFilter                   = AstFilter.Eq(discriminatorField, discriminatorValue);
                    var actualTypeSerializer           = context.KnownSerializersRegistry.GetSerializer(sourceExpression);
                    var enumerableActualTypeSerializer = IEnumerableSerializer.Create(actualTypeSerializer);
                    var actualTypeSourceField          = AstFilter.Field(sourceField.Path, enumerableActualTypeSerializer);
                    var combinedFilter                 = AstFilter.Combine(sourceFilter, ofTypeFilter);

                    return(actualTypeSourceField, combinedFilter);
                }

                if (method.Is(EnumerableMethod.Where))
                {
                    var whereSourceExpression = arguments[0];
                    var(sourceField, sourceFilter) = Translate(context, whereSourceExpression);

                    var predicateLambda     = (LambdaExpression)arguments[1];
                    var parameterExpression = predicateLambda.Parameters.Single();
                    var itemSerializer      = ArraySerializerHelper.GetItemSerializer(sourceField.Serializer);
                    var parameterSymbol     = context.CreateSymbol(parameterExpression, "@<elem>", itemSerializer); // @<elem> represents the implied element
                    var predicateContext    = context.WithSingleSymbol(parameterSymbol);                            // @<elem> is the only symbol visible inside an $elemMatch
                    var whereFilter         = ExpressionToFilterTranslator.Translate(predicateContext, predicateLambda.Body, exprOk: false);
                    var combinedFilter      = AstFilter.Combine(sourceFilter, whereFilter);

                    return(sourceField, combinedFilter);
                }
            }

            var field = ExpressionToFilterFieldTranslator.Translate(context, sourceExpression);

            return(field, null);
        }
        public static AggregationExpression Translate(TranslationContext context, MethodCallExpression expression)
        {
            var method    = expression.Method;
            var arguments = expression.Arguments;

            if (method.Is(EnumerableMethod.Reverse))
            {
                var sourceExpression  = arguments[0];
                var sourceTranslation = ExpressionToAggregationExpressionTranslator.TranslateEnumerable(context, sourceExpression);
                var ast            = AstExpression.ReverseArray(sourceTranslation.Ast);
                var itemSerializer = ArraySerializerHelper.GetItemSerializer(sourceTranslation.Serializer);
                var serializer     = IEnumerableSerializer.Create(itemSerializer);
                return(new AggregationExpression(expression, ast, serializer));
            }

            throw new ExpressionNotSupportedException(expression);
        }
Example #7
0
        public static AggregationExpression TranslateEnumerable(TranslationContext context, Expression expression)
        {
            var aggregateExpression = Translate(context, expression);

            var serializer = aggregateExpression.Serializer;

            if (serializer is IWrappedEnumerableSerializer wrappedEnumerableSerializer)
            {
                var enumerableFieldName         = wrappedEnumerableSerializer.EnumerableFieldName;
                var enumerableElementSerializer = wrappedEnumerableSerializer.EnumerableElementSerializer;
                var enumerableSerializer        = IEnumerableSerializer.Create(enumerableElementSerializer);
                var ast = AstExpression.GetField(aggregateExpression.Ast, enumerableFieldName);

                return(new AggregationExpression(aggregateExpression.Expression, ast, enumerableSerializer));
            }

            return(aggregateExpression);
        }
Example #8
0
        // private methods
        private HashSet <IBsonSerializer> GetPossibleSerializersAtThisLevel(Type type)
        {
            if (_knownSerializers.TryGetValue(type, out var knownSerializers))
            {
                return(knownSerializers);
            }

            Type itemType = null;

            if (type.TryGetIEnumerableGenericInterface(out var ienumerableGenericInterface))
            {
                itemType = ienumerableGenericInterface.GetGenericArguments()[0];
            }

            var possibleSerializers = new HashSet <IBsonSerializer>();

            foreach (var serializer in _knownSerializers.Values.SelectMany(hashset => hashset))
            {
                var valueType = serializer.ValueType;
                if (valueType == type || valueType.IsEnum() && Enum.GetUnderlyingType(valueType) == type)
                {
                    possibleSerializers.Add(serializer);
                }

                if (serializer is IBsonArraySerializer arraySerializer && arraySerializer.TryGetItemSerializationInfo(out var itemSerializationInfo))
                {
                    var itemSerializer = itemSerializationInfo.Serializer;
                    if (itemSerializer.ValueType == type)
                    {
                        possibleSerializers.Add(itemSerializer);
                    }
                }

                if (valueType == itemType)
                {
                    var ienumerableSerializer = IEnumerableSerializer.Create(serializer);
                    possibleSerializers.Add(ienumerableSerializer);
                }
            }

            return(possibleSerializers);
        }
        private static AstPipeline TranslateResultSelector(
            TranslationContext context,
            AstPipeline pipeline,
            ReadOnlyCollection <Expression> arguments,
            IBsonSerializer keySerializer,
            IBsonSerializer elementSerializer)
        {
            var resultSelectorLambda = ExpressionHelper.UnquoteLambda(arguments.Last());
            var root                      = AstExpression.Var("ROOT", isCurrent: true);
            var keyParameter              = resultSelectorLambda.Parameters[0];
            var keyField                  = AstExpression.GetField(root, "_id");
            var keySymbol                 = context.CreateSymbol(keyParameter, keyField, keySerializer);
            var elementsParameter         = resultSelectorLambda.Parameters[1];
            var elementsField             = AstExpression.GetField(root, "_elements");
            var elementsSerializer        = IEnumerableSerializer.Create(elementSerializer);
            var elementsSymbol            = context.CreateSymbol(elementsParameter, elementsField, elementsSerializer);
            var resultSelectContext       = context.WithSymbols(keySymbol, elementsSymbol);
            var resultSelectorTranslation = ExpressionToAggregationExpressionTranslator.Translate(resultSelectContext, resultSelectorLambda.Body);

            var(projectStage, projectionSerializer) = ProjectionHelper.CreateProjectStage(resultSelectorTranslation);
            return(pipeline.AddStages(projectionSerializer, projectStage));
        }
        public static AggregationExpression Translate(TranslationContext context, MethodCallExpression expression)
        {
            var method    = expression.Method;
            var arguments = expression.Arguments;

            if (method.Is(EnumerableMethod.Range))
            {
                var startExpression  = arguments[0];
                var startTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, startExpression);
                var(startVar, startAst) = AstExpression.UseVarIfNotSimple("start", startTranslation.Ast);
                var countExpression  = arguments[1];
                var countTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, countExpression);
                var(countVar, countAst) = AstExpression.UseVarIfNotSimple("count", countTranslation.Ast);
                var ast = AstExpression.Let(
                    startVar,
                    countVar,
                    AstExpression.Range(startAst, end: AstExpression.Add(startAst, countAst)));
                var serializer = IEnumerableSerializer.Create(new Int32Serializer());
                return(new AggregationExpression(expression, ast, serializer));
            }

            throw new ExpressionNotSupportedException(expression);
        }
Example #11
0
        public static AggregationExpression Translate(TranslationContext context, MethodCallExpression expression)
        {
            var method    = expression.Method;
            var arguments = expression.Arguments;

            if (method.Is(EnumerableMethod.Take))
            {
                var        sourceExpression = arguments[0];
                var        countExpression  = arguments[1];
                Expression skipExpression   = null;
                if (sourceExpression is MethodCallExpression sourceSkipExpression && sourceSkipExpression.Method.Is(EnumerableMethod.Skip))
                {
                    sourceExpression = sourceSkipExpression.Arguments[0];
                    skipExpression   = sourceSkipExpression.Arguments[1];
                }

                var           sourceTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, sourceExpression);
                var           countTranslation  = ExpressionToAggregationExpressionTranslator.Translate(context, countExpression);
                AstExpression ast;
                if (skipExpression == null)
                {
                    ast = AstExpression.Slice(sourceTranslation.Ast, countTranslation.Ast);
                }
                else
                {
                    var skipTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, skipExpression);
                    ast = AstExpression.Slice(sourceTranslation.Ast, skipTranslation.Ast, countTranslation.Ast);
                }
                var itemSerializer = ArraySerializerHelper.GetItemSerializer(sourceTranslation.Serializer);
                var serializer     = IEnumerableSerializer.Create(itemSerializer);

                return(new AggregationExpression(expression, ast, serializer));
            }

            throw new ExpressionNotSupportedException(expression);
        }
Example #12
0
        public static AggregationExpression Translate(TranslationContext context, MethodCallExpression expression)
        {
            var method    = expression.Method;
            var arguments = expression.Arguments;

            if (method.IsOneOf(EnumerableMethod.Where, MongoEnumerableMethod.WhereWithLimit))
            {
                var sourceExpression  = arguments[0];
                var sourceTranslation = ExpressionToAggregationExpressionTranslator.TranslateEnumerable(context, sourceExpression);
                var itemSerializer    = ArraySerializerHelper.GetItemSerializer(sourceTranslation.Serializer);

                var predicateLambda      = (LambdaExpression)arguments[1];
                var predicateParameter   = predicateLambda.Parameters[0];
                var predicateSymbol      = context.CreateSymbol(predicateParameter, itemSerializer);
                var predicateContext     = context.WithSymbol(predicateSymbol);
                var predicateTranslation = ExpressionToAggregationExpressionTranslator.Translate(predicateContext, predicateLambda.Body);

                AggregationExpression limitTranslation = null;
                if (method.Is(MongoEnumerableMethod.WhereWithLimit))
                {
                    var limitExpression = arguments[2];
                    limitTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, limitExpression);
                }

                var ast = AstExpression.Filter(
                    sourceTranslation.Ast,
                    predicateTranslation.Ast,
                    predicateParameter.Name,
                    limitTranslation?.Ast);

                var enumerableSerializer = IEnumerableSerializer.Create(itemSerializer);
                return(new AggregationExpression(expression, ast, enumerableSerializer));
            }

            throw new ExpressionNotSupportedException(expression);
        }