Example #1
0
        private static AstPipeline TranslateSelectManyWithCollectionSelectorAndNonIdentityResultSelector(
            TranslationContext context,
            AstPipeline pipeline,
            AggregationExpression collectionSelectorTranslation,
            LambdaExpression resultSelectorLambda)

        {
            var sourceSerializer         = pipeline.OutputSerializer;
            var collectionItemSerializer = ArraySerializerHelper.GetItemSerializer(collectionSelectorTranslation.Serializer);

            var resultSelectorSourceParameterExpression = resultSelectorLambda.Parameters[0];
            var resultSelectorSourceAst                         = AstExpression.Var("ROOT", isCurrent: true);
            var resultSelectorSourceParameterSymbol             = context.CreateSymbol(resultSelectorSourceParameterExpression, resultSelectorSourceAst, sourceSerializer, isCurrent: true);
            var resultSelectorCollectionItemParameterExpression = resultSelectorLambda.Parameters[1];
            var resultSelectorCollectionItemParameterSymbol     = context.CreateSymbol(resultSelectorCollectionItemParameterExpression, collectionItemSerializer);
            var resultSelectorContext        = context.WithSymbols(resultSelectorSourceParameterSymbol, resultSelectorCollectionItemParameterSymbol);
            var resultSelectorTranslation    = ExpressionToAggregationExpressionTranslator.Translate(resultSelectorContext, resultSelectorLambda.Body);
            var resultValueSerializer        = resultSelectorTranslation.Serializer;
            var resultWrappedValueSerializer = WrappedValueSerializer.Create("_v", resultValueSerializer);
            var resultAst = AstExpression.Map(
                input: collectionSelectorTranslation.Ast,
                @as: resultSelectorCollectionItemParameterSymbol.Var,
                @in: resultSelectorTranslation.Ast);

            return(pipeline.AddStages(
                       resultWrappedValueSerializer,
                       AstStage.Project(
                           AstProject.Set("_v", resultAst),
                           AstProject.ExcludeId()),
                       AstStage.Unwind("_v")));
        }
        public void DifferentAggregationModifier()
        {
            var dataInfo         = new TestStreamedValueInfo(typeof(int));
            var selectProjection = Expression.Constant(1);
            var selectProjectionWithCountAggregation = new AggregationExpression(typeof(int), selectProjection, AggregationModifier.Count);

            var sqlStatement1 = new SqlStatement(
                dataInfo,
                selectProjectionWithCountAggregation,
                new SqlTable[] { },
                null,
                null,
                new Ordering[] { },
                null,
                false,
                null,
                null);

            var sqlStatement2 = new SqlStatement(
                dataInfo,
                selectProjection,
                new SqlTable[] { },
                null,
                null,
                new Ordering[] { },
                null,
                false,
                null,
                null);

            Assert.That(sqlStatement1.Equals(sqlStatement2), Is.False);
        }
Example #3
0
            private BsonValue BuildAggregation(AggregationExpression node)
            {
                switch (node.AggregationType)
                {
                case AggregationType.AddToSet:
                    return(new BsonDocument("$addToSet", BuildValue(node.Argument)));

                case AggregationType.Average:
                    return(new BsonDocument("$avg", BuildValue(node.Argument)));

                case AggregationType.First:
                    return(new BsonDocument("$first", BuildValue(node.Argument)));

                case AggregationType.Last:
                    return(new BsonDocument("$last", BuildValue(node.Argument)));

                case AggregationType.Max:
                    return(new BsonDocument("$max", BuildValue(node.Argument)));

                case AggregationType.Min:
                    return(new BsonDocument("$min", BuildValue(node.Argument)));

                case AggregationType.Push:
                    return(new BsonDocument("$push", BuildValue(node.Argument)));

                case AggregationType.Sum:
                    return(new BsonDocument("$sum", BuildValue(node.Argument)));
                }

                // we should never ever get here.
                throw new MongoInternalException("Unrecognized aggregation type.");
            }
Example #4
0
        public void VisitAggregationExpression_Count()
        {
            var columnExpression = new SqlColumnDefinitionExpression(typeof(string), "c", "Name", false);
            var expression       = new AggregationExpression(typeof(int), columnExpression, AggregationModifier.Count);

            SqlGeneratingExpressionVisitor.GenerateSql(expression, _commandBuilder, _stageMock);

            Assert.That(_commandBuilder.GetCommandText(), Is.EqualTo("COUNT(*)"));
        }
Example #5
0
        public void VisitAggregationExpression_Average()
        {
            var columnExpression = new NamedExpression(null, new SqlColumnDefinitionExpression(typeof(string), "c", "Name", false));
            var expression       = new AggregationExpression(typeof(double), columnExpression, AggregationModifier.Average);

            SqlGeneratingExpressionVisitor.GenerateSql(expression, _commandBuilder, _stageMock);

            Assert.That(_commandBuilder.GetCommandText(), Is.EqualTo("AVG([c].[Name])"));
        }
 // public static methods
 public static (AstProjectStage, IBsonSerializer) CreateProjectStage(AggregationExpression expression)
 {
     if (expression.Ast.NodeType == AstNodeType.ComputedDocumentExpression)
     {
         return(CreateComputedDocumentProjectStage(expression));
     }
     else
     {
         return(CreateWrappedValueProjectStage(expression));
     }
 }
Example #7
0
        private bool TryBindAggregationExpression(MethodCallExpression node, out Expression aggregationNode)
        {
            AggregationType aggregationType;

            if (TryGetAggregationType(node.Method.Name, out aggregationType))
            {
                var argument = GetAggregationArgument(node);
                aggregationNode = new AggregationExpression(node.Type, aggregationType, argument);
                return(true);
            }

            aggregationNode = null;
            return(false);
        }
        public void CreateExpression_HasAggregationModifier()
        {
            var sqlStatementBuilder = new SqlStatementBuilder(SqlStatementModelObjectMother.CreateSqlStatement());

            sqlStatementBuilder.SqlTables.Clear();
            var selectProjection = new AggregationExpression(typeof(double), sqlStatementBuilder.SelectProjection, AggregationModifier.Max);

            sqlStatementBuilder.SelectProjection = selectProjection;
            var sqlStatement = sqlStatementBuilder.GetSqlStatement();

            var result = sqlStatement.CreateExpression();

            Assert.That(result, Is.SameAs(selectProjection));
        }
Example #9
0
        private static AstPipeline TranslateSelectManyWithCollectionSelectorAndIdentityResultSelector(
            AstPipeline pipeline,
            AggregationExpression collectionSelectorTranslation)
        {
            var collectionItemSerializer     = ArraySerializerHelper.GetItemSerializer(collectionSelectorTranslation.Serializer);
            var resultValueSerializer        = collectionItemSerializer;
            var resultWrappedValueSerializer = WrappedValueSerializer.Create("_v", resultValueSerializer);

            return(pipeline.AddStages(
                       resultWrappedValueSerializer,
                       AstStage.Project(
                           AstProject.Set("_v", collectionSelectorTranslation.Ast),
                           AstProject.ExcludeId()),
                       AstStage.Unwind("_v")));
        }
Example #10
0
        public void BuildSelectPart_WithAggregation()
        {
            var aggregationExpression = new AggregationExpression(typeof(int), _entityExpression, AggregationModifier.Count);
            var sqlStatement = new SqlStatementBuilder {
                SelectProjection = aggregationExpression, DataInfo = new TestStreamedValueInfo(typeof(object))
            }.GetSqlStatement();

            _stageMock.Expect(
                mock => mock.GenerateTextForSelectExpression(_commandBuilder, aggregationExpression))
            .WhenCalled(mi => ((SqlCommandBuilder)mi.Arguments[0]).Append("COUNT(*)"));

            _generator.BuildSelectPart(sqlStatement, _commandBuilder, false);

            Assert.That(_commandBuilder.GetCommandText(), Is.EqualTo("SELECT COUNT(*)"));
            _stageMock.VerifyAllExpectations();
        }
Example #11
0
        public void BuildSelectPart_WithAggregation()
        {
            var aggregationExpression = new AggregationExpression(typeof(int), ExpressionHelper.CreateExpression(), AggregationModifier.Count);
            var sqlStatement          = SqlStatementModelObjectMother.CreateMinimalSqlStatement(new SqlStatementBuilder {
                SelectProjection = aggregationExpression
            });

            _stageMock.Expect(
                mock => mock.GenerateTextForSelectExpression(_commandBuilder, aggregationExpression))
            .WhenCalled(mi => ((SqlCommandBuilder)mi.Arguments[0]).Append("COUNT(*)"));

            _generator.BuildSelectPart(sqlStatement, _commandBuilder, false);

            Assert.That(_commandBuilder.GetCommandText(), Is.EqualTo("SELECT COUNT(*)"));
            _stageMock.VerifyAllExpectations();
        }
        public void GetSqlStatement_CheckProperties()
        {
            var dataInfo                      = new TestStreamedValueInfo(typeof(Cook));
            var topExpression                 = ExpressionHelper.CreateExpression();
            var isDistinctQuery               = BooleanObjectMother.GetRandomBoolean();
            var selectProjection              = new AggregationExpression(typeof(int), Expression.Constant(1), AggregationModifier.Min);
            var whereCondition                = Expression.Constant(true);
            var sqlTable                      = new SqlTable(new ResolvedSimpleTableInfo(typeof(Cook), "CookTable", "c"), JoinSemantics.Inner);
            var ordering                      = new Ordering(Expression.Constant("order"), OrderingDirection.Desc);
            var rowNumberSelector             = Expression.Constant("selector");
            var currentRowNumberOffset        = Expression.Constant(1);
            var groupExpression               = Expression.Constant("group");
            var setOperationCombinedStatement = SqlStatementModelObjectMother.CreateSetOperationCombinedStatement();

            var statementBuilder = new SqlStatementBuilder
            {
                DataInfo                       = dataInfo,
                TopExpression                  = topExpression,
                IsDistinctQuery                = isDistinctQuery,
                SelectProjection               = selectProjection,
                SqlTables                      = { sqlTable },
                WhereCondition                 = whereCondition,
                RowNumberSelector              = rowNumberSelector,
                CurrentRowNumberOffset         = currentRowNumberOffset,
                GroupByExpression              = groupExpression,
                Orderings                      = { ordering },
                SetOperationCombinedStatements = { setOperationCombinedStatement }
            };

            var sqlStatement = statementBuilder.GetSqlStatement();

            Assert.That(sqlStatement.DataInfo, Is.SameAs(dataInfo));
            Assert.That(sqlStatement.TopExpression, Is.SameAs(topExpression));
            Assert.That(sqlStatement.IsDistinctQuery, Is.EqualTo(isDistinctQuery));
            Assert.That(sqlStatement.SelectProjection, Is.SameAs(selectProjection));
            Assert.That(sqlStatement.SqlTables, Is.EqualTo(new[] { sqlTable }));
            Assert.That(sqlStatement.Orderings, Is.EqualTo(new[] { ordering }));
            Assert.That(sqlStatement.WhereCondition, Is.SameAs(whereCondition));
            Assert.That(sqlStatement.RowNumberSelector, Is.SameAs(rowNumberSelector));
            Assert.That(sqlStatement.CurrentRowNumberOffset, Is.SameAs(currentRowNumberOffset));
            Assert.That(sqlStatement.GroupByExpression, Is.SameAs(groupExpression));
            Assert.That(sqlStatement.SetOperationCombinedStatements, Is.EqualTo(new[] { setOperationCombinedStatement }));
        }
Example #13
0
        private static ValueResult RunAggregationExpression(AggregationExpression expr, RunContext ctx)
        {
            var dice          = ctx.Variables.GetVariableValue <RollResult>(expr.Variable);
            var options       = MergeOptions(expr.Options);
            var filteredDices = FilterDices(
                dice.Dices,
                options.Filter ?? new FilterOption {
                Type = FilterType.None
            },
                options.Ranking ?? new RankingOption {
                Type = RankingType.None
            },
                ctx.Variables);
            var result = ComputeResult(filteredDices, options.Aggregation);

            return(new ValueResult {
                Result = result, Name = expr.Name
            });
        }
Example #14
0
        public virtual Expression VisitAggregationExpression(AggregationExpression expression)
        {
            ArgumentUtility.CheckNotNull("expression", expression);

            if (expression.AggregationModifier == AggregationModifier.Count)
            {
                _commandBuilder.Append("COUNT(*)");
                return(expression);
            }

            if (expression.AggregationModifier == AggregationModifier.Average)
            {
                _commandBuilder.Append("AVG");
            }
            else if (expression.AggregationModifier == AggregationModifier.Max)
            {
                _commandBuilder.Append("MAX");
            }
            else if (expression.AggregationModifier == AggregationModifier.Min)
            {
                _commandBuilder.Append("MIN");
            }
            else if (expression.AggregationModifier == AggregationModifier.Sum)
            {
                _commandBuilder.Append("SUM");
            }
            else
            {
                var message = string.Format(
                    "Cannot generate SQL for aggregation '{0}'. Expression: '{1}'",
                    expression.AggregationModifier,
                    FormattingExpressionTreeVisitor.Format(expression));
                throw new NotSupportedException(message);
            }

            _commandBuilder.Append("(");

            VisitExpression(expression.Expression);
            _commandBuilder.Append(")");

            return(expression);
        }
Example #15
0
        public void SetUp()
        {
            _dataInfo = new StreamedScalarValueInfo(typeof(int));

            _resolvedElementExpressionReference = new SqlColumnDefinitionExpression(typeof(string), "q0", "element", false);
            _resolvedSelectProjection           = new NamedExpression(
                null,
                new AggregationExpression(typeof(int), _resolvedElementExpressionReference, AggregationModifier.Min));

            _associatedGroupingSelectExpression = new SqlGroupingSelectExpression(
                new NamedExpression("key", Expression.Constant("k")),
                new NamedExpression("element", Expression.Constant("e")));

            _resolvedJoinedGroupingSubStatement = SqlStatementModelObjectMother.CreateSqlStatement(_associatedGroupingSelectExpression);
            _resolvedJoinedGroupingTable        = new SqlTable(
                new ResolvedJoinedGroupingTableInfo(
                    "q1",
                    _resolvedJoinedGroupingSubStatement,
                    _associatedGroupingSelectExpression,
                    "q0"), JoinSemantics.Inner);

            _simplifiableResolvedSqlStatement = new SqlStatement(
                _dataInfo,
                _resolvedSelectProjection,
                new[] { _resolvedJoinedGroupingTable },
                null,
                null,
                new Ordering[0],
                null,
                false,
                Expression.Constant(0),
                Expression.Constant(0));
            _simplifiableUnresolvedProjection = new AggregationExpression(
                typeof(int),
                new SqlTableReferenceExpression(_resolvedJoinedGroupingTable),
                AggregationModifier.Count);

            _stageMock = MockRepository.GenerateStrictMock <IMappingResolutionStage> ();
            _context   = new MappingResolutionContext();

            _groupAggregateSimplifier = new GroupAggregateSimplifier(_stageMock, _context);
        }
        public void SimplifyIfPossible_WithNonSimplifiableProjection_ReturnsOriginalStatement()
        {
            Assert.That(_associatedGroupingSelectExpression.AggregationExpressions.Count, Is.EqualTo(0));
            var expression = new SqlSubStatementExpression(_simplifiableResolvedSqlStatement);

            _stageMock.Replay();

            var nonSimplifiableProjection = new AggregationExpression(
                typeof(int),
                new SqlTableReferenceExpression(SqlStatementModelObjectMother.CreateSqlTable()), AggregationModifier.Count);
            var result = _groupAggregateSimplifier.SimplifyIfPossible(expression, nonSimplifiableProjection);

            _stageMock.VerifyAllExpectations();

            var expected = new SqlSubStatementExpression(_simplifiableResolvedSqlStatement);

            SqlExpressionTreeComparer.CheckAreEqualTrees(expected, result);

            Assert.That(_associatedGroupingSelectExpression.AggregationExpressions.Count, Is.EqualTo(0));
        }
        private static bool TryTranslateInstanceToStringWithNoArguments(TranslationContext context, MethodCallExpression expression, out AggregationExpression translation)
        {
            var method    = expression.Method;
            var arguments = expression.Arguments;

            translation = null;

            if (method.IsStatic || method.ReturnType != typeof(string) || method.Name != "ToString" || arguments.Count != 0)
            {
                return(false);
            }

            var objectExpression = expression.Object;

            var objectTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, objectExpression);
            var ast = AstExpression.ToString(objectTranslation.Ast);

            translation = new AggregationExpression(expression, ast, new StringSerializer());
            return(true);
        }
        private static bool TryTranslateDateTimeToStringWithFormat(TranslationContext context, MethodCallExpression expression, out AggregationExpression translation)
        {
            var method    = expression.Method;
            var arguments = expression.Arguments;

            if (method.DeclaringType != typeof(DateTime) || method.IsStatic || method.ReturnType != typeof(string) || method.Name != "ToString" || arguments.Count != 1 || arguments[0].Type != typeof(string))
            {
                translation = null;
                return(false);
            }

            var dateTimeExpression  = expression.Object;
            var dateTimeTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, dateTimeExpression);
            var formatExpression    = arguments[0];
            var formatTranslation   = ExpressionToAggregationExpressionTranslator.Translate(context, formatExpression);
            var ast = AstExpression.DateToString(dateTimeTranslation.Ast, formatTranslation.Ast);

            translation = new AggregationExpression(expression, ast, new StringSerializer());
            return(true);
        }
        public Expression VisitAggregation(AggregationExpression expression)
        {
            Expression newInnerExpression;

            if (expression.AggregationModifier == AggregationModifier.Count)
            {
                newInnerExpression = ApplyValueContext(expression.Expression);
            }
            else
            {
                newInnerExpression = ApplySingleValueContext(expression.Expression);
            }

            if (newInnerExpression != expression.Expression)
            {
                return(new AggregationExpression(expression.Type, newInnerExpression, expression.AggregationModifier));
            }

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

            if (IsStandardDeviationMethod(method, out var stddevOperator))
            {
                if (arguments.Count == 1 || arguments.Count == 2)
                {
                    var sourceExpression  = arguments[0];
                    var sourceTranslation = ExpressionToAggregationExpressionTranslator.TranslateEnumerable(context, sourceExpression);

                    if (arguments.Count == 2)
                    {
                        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 selectorTranslation         = ExpressionToAggregationExpressionTranslator.Translate(selectorContext, selectorLambda.Body);
                        var selectorAst = AstExpression.Map(
                            input: sourceTranslation.Ast,
                            @as: selectorParameterSymbol.Var,
                            @in: selectorTranslation.Ast);
                        var selectorResultSerializer = BsonSerializer.LookupSerializer(selectorLambda.ReturnType);
                        sourceTranslation = new AggregationExpression(selectorLambda, selectorAst, selectorResultSerializer);
                    }

                    var ast        = AstExpression.StdDev(stddevOperator, sourceTranslation.Ast);
                    var serializer = BsonSerializer.LookupSerializer(expression.Type);
                    return(new AggregationExpression(expression, ast, serializer));
                }
            }

            if (SetWindowFieldsMethodToAggregationExpressionTranslator.CanTranslate(expression))
            {
                return(SetWindowFieldsMethodToAggregationExpressionTranslator.Translate(context, expression));
            }

            throw new ExpressionNotSupportedException(expression);
        }
Example #21
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);
        }
        public void SimplifyIfPossible_SimplifiableStatement_AddsAggregationAndReturnsReference()
        {
            Assert.That(_associatedGroupingSelectExpression.AggregationExpressions.Count, Is.EqualTo(0));

            var expression = new SqlSubStatementExpression(_simplifiableResolvedSqlStatement);

            var preparedResolvedAggregate = new AggregationExpression(
                typeof(int),
                new NamedExpression("element", Expression.Constant("e")),
                AggregationModifier.Count);

            _stageMock
            .Expect(mock => mock.ResolveAggregationExpression(Arg <Expression> .Is.Anything, Arg.Is(_context)))
            .Return(preparedResolvedAggregate)
            .WhenCalled(mi => {
                var expectedReplacedAggregate = new AggregationExpression(
                    typeof(int),
                    ((NamedExpression)_associatedGroupingSelectExpression.ElementExpression).Expression,
                    AggregationModifier.Count);
                SqlExpressionTreeComparer.CheckAreEqualTrees(expectedReplacedAggregate, (Expression)mi.Arguments[0]);
            });
            _stageMock.Replay();

            var result = _groupAggregateSimplifier.SimplifyIfPossible(expression, _simplifiableUnresolvedProjection);

            _stageMock.VerifyAllExpectations();

            Assert.That(_associatedGroupingSelectExpression.AggregationExpressions.Count, Is.EqualTo(1));
            Assert.That(
                ((NamedExpression)_associatedGroupingSelectExpression.AggregationExpressions[0]).Expression,
                Is.SameAs(preparedResolvedAggregate));

            var expected = new SqlColumnDefinitionExpression(typeof(int), "q0", "a0", false);

            SqlExpressionTreeComparer.CheckAreEqualTrees(expected, result);
        }
 public void SetUp()
 {
     _wrappedExpression    = Expression.Constant(1);
     _aggregationEpression = new AggregationExpression(typeof(int), _wrappedExpression, AggregationModifier.Max);
 }
        public static AggregationExpression Translate(TranslationContext context, MethodCallExpression expression)
        {
            var method    = expression.Method;
            var arguments = expression.Arguments;

            if (CanTranslate(expression))
            {
                Expression objectExpression;
                if (method.Is(EnumerableMethod.Contains))
                {
                    objectExpression = arguments[0];
                    arguments        = new ReadOnlyCollection <Expression>(arguments.Skip(1).ToList());

                    if (objectExpression.Type != typeof(string))
                    {
                        throw new ExpressionNotSupportedException(objectExpression, expression, because: "type implementing IEnumerable<char> is not string");
                    }
                }
                else
                {
                    objectExpression = expression.Object;
                }

                var objectTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, objectExpression);
                var valueExpression   = arguments[0];
                AggregationExpression valueTranslation;
                if (valueExpression.Type == typeof(char) &&
                    valueExpression is ConstantExpression constantValueExpression)
                {
                    var c     = (char)constantValueExpression.Value;
                    var value = new string(c, 1);
                    valueTranslation = new AggregationExpression(valueExpression, value, objectTranslation.Serializer);
                }
                else
                {
                    valueTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, valueExpression);
                    if (valueTranslation.Serializer is IRepresentationConfigurable representationConfigurable &&
                        representationConfigurable.Representation != BsonType.String)
                    {
                        throw new ExpressionNotSupportedException(valueExpression, expression, because: "it is not serialized as a string");
                    }
                }
                bool ignoreCase = false;
                if (IsWithComparisonTypeMethod(method))
                {
                    var comparisonTypeExpression = arguments[1];
                    ignoreCase = GetIgnoreCaseFromComparisonType(comparisonTypeExpression);
                }
                if (IsWithIgnoreCaseAndCultureMethod(method))
                {
                    var ignoreCaseExpression = arguments[1];
                    var cultureExpression    = arguments[2];
                    ignoreCase = GetIgnoreCaseFromIgnoreCaseAndCulture(ignoreCaseExpression, cultureExpression);
                }
                var stringAst    = objectTranslation.Ast;
                var substringAst = valueTranslation.Ast;
                if (ignoreCase)
                {
                    stringAst    = AstExpression.ToLower(stringAst);
                    substringAst = AstExpression.ToLower(substringAst);
                }
                var ast = CreateAst(method.Name, stringAst, substringAst);
                return(new AggregationExpression(expression, ast, new BooleanSerializer()));
            }

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

            if (method.IsOneOf(__windowMethods))
            {
                var partitionExpression  = arguments[0];
                var partitionTranslation = ExpressionToAggregationExpressionTranslator.TranslateEnumerable(context, partitionExpression);
                var partitionSerializer  = (ISetWindowFieldsPartitionSerializer)partitionTranslation.Serializer;
                var inputSerializer      = partitionSerializer.InputSerializer;

                AstWindow window = null;
                if (HasArgument <Expression>(parameters, "window", arguments, out var windowExpression))
                {
                    window = TranslateWindow(context, expression, windowExpression, inputSerializer);
                }

                if (method.IsOneOf(__nullaryMethods))
                {
                    var @operator  = GetNullaryWindowOperator(method);
                    var ast        = AstExpression.NullaryWindowExpression(@operator, window);
                    var serializer = BsonSerializer.LookupSerializer(method.ReturnType); // TODO: use correct serializer
                    return(new AggregationExpression(expression, ast, serializer));
                }

                AggregationExpression selectorTranslation = null;
                if (HasArgument <LambdaExpression>(parameters, "selector", arguments, out var selectorLambda))
                {
                    selectorTranslation = TranslateSelector(context, selectorLambda, inputSerializer);
                }

                if (method.IsOneOf(__unaryMethods))
                {
                    var @operator  = GetUnaryWindowOperator(method);
                    var ast        = AstExpression.UnaryWindowExpression(@operator, selectorTranslation.Ast, window);
                    var serializer = BsonSerializer.LookupSerializer(method.ReturnType); // TODO: use correct serializer
                    return(new AggregationExpression(expression, ast, serializer));
                }

                if (method.IsOneOf(__binaryMethods))
                {
                    var selector1Lambda      = GetArgument <LambdaExpression>(parameters, "selector1", arguments);
                    var selector2Lambda      = GetArgument <LambdaExpression>(parameters, "selector2", arguments);
                    var selector1Translation = TranslateSelector(context, selector1Lambda, inputSerializer);
                    var selector2Translation = TranslateSelector(context, selector2Lambda, inputSerializer);

                    var @operator  = GetBinaryWindowOperator(method);
                    var ast        = AstExpression.BinaryWindowExpression(@operator, selector1Translation.Ast, selector2Translation.Ast, window);
                    var serializer = BsonSerializer.LookupSerializer(method.ReturnType); // TODO: use correct serializer
                    return(new AggregationExpression(expression, ast, serializer));
                }

                if (method.IsOneOf(__derivativeOrIntegralMethods))
                {
                    WindowTimeUnit?unit = default;
                    if (HasArgument <Expression>(parameters, "unit", arguments, out var unitExpression))
                    {
                        unit = unitExpression.GetConstantValue <WindowTimeUnit>(expression);
                    }

                    var @operator  = GetDerivativeOrIntegralWindowOperator(method);
                    var ast        = AstExpression.DerivativeOrIntegralWindowExpression(@operator, selectorTranslation.Ast, unit, window);
                    var serializer = BsonSerializer.LookupSerializer(method.ReturnType); // TODO: use correct serializer
                    return(new AggregationExpression(expression, ast, serializer));
                }

                if (method.IsOneOf(__exponentialMovingAverageMethods))
                {
                    var weightingExpression = arguments[2];
                    var weighting           = weightingExpression.GetConstantValue <ExponentialMovingAverageWeighting>(expression);

                    var ast        = AstExpression.ExponentialMovingAverageWindowExpression(selectorTranslation.Ast, weighting, window);
                    var serializer = BsonSerializer.LookupSerializer(method.ReturnType); // TODO: use correct serializer
                    return(new AggregationExpression(expression, ast, serializer));
                }

                if (method.IsOneOf(__shiftMethods))
                {
                    var byExpression = arguments[2];
                    var by           = byExpression.GetConstantValue <int>(expression);

                    AstExpression defaultValue = null;
                    if (method.Is(WindowMethod.ShiftWithDefaultValue))
                    {
                        var defaultValueExpression  = arguments[3];
                        var defaultValueTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, defaultValueExpression);
                        defaultValue = defaultValueTranslation.Ast;
                    }

                    var ast        = AstExpression.ShiftWindowExpression(selectorTranslation.Ast, by, defaultValue);
                    var serializer = BsonSerializer.LookupSerializer(method.ReturnType); // TODO: use correct serializer
                    return(new AggregationExpression(expression, ast, serializer));
                }
            }

            throw new ExpressionNotSupportedException(expression);
        }
        // private static methods
        private static (AstProjectStage, IBsonSerializer) CreateComputedDocumentProjectStage(AggregationExpression expression)
        {
            var computedDocument = (AstComputedDocumentExpression)expression.Ast;

            var specifications = new List <AstProjectStageSpecification>();

            var isIdProjected = false;

            foreach (var computedField in computedDocument.Fields)
            {
                var path  = computedField.Path;
                var value = computedField.Value;

                if (value is AstConstantExpression astConstantExpression)
                {
                    if (ValueNeedsToBeQuoted(astConstantExpression.Value))
                    {
                        value = AstExpression.Literal(value);
                    }
                }
                specifications.Add(AstProject.Set(path, value));
                isIdProjected |= path == "_id";
            }

            if (!isIdProjected)
            {
                specifications.Add(AstProject.ExcludeId());
            }

            var projectStage = AstStage.Project(specifications);

            return(projectStage, expression.Serializer);

            bool ValueNeedsToBeQuoted(BsonValue constantValue)
            {
                switch (constantValue.BsonType)
                {
                case BsonType.Boolean:
                case BsonType.Decimal128:
                case BsonType.Double:
                case BsonType.Int32:
                case BsonType.Int64:
                    return(true);

                default:
                    return(false);
                }
            }
        }
        private static (AstProjectStage, IBsonSerializer) CreateWrappedValueProjectStage(AggregationExpression expression)
        {
            var wrappedValueSerializer = WrappedValueSerializer.Create("_v", expression.Serializer);
            var projectStage           =
                AstStage.Project(
                    AstProject.Set("_v", expression.Ast),
                    AstProject.ExcludeId());

            return(projectStage, wrappedValueSerializer);
        }