Beispiel #1
0
        public static AggregationExpression Translate(TranslationContext context, UnaryExpression expression)
        {
            if (expression.NodeType == ExpressionType.Convert)
            {
                var operandExpression  = expression.Operand;
                var operandTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, operandExpression);

                var expressionType = expression.Type;
                if (expressionType.IsConstructedGenericType && expressionType.GetGenericTypeDefinition() == typeof(Nullable <>))
                {
                    var valueType = expressionType.GetGenericArguments()[0];
                    if (operandExpression.Type == valueType)
                    {
                        // use the same AST but with a new nullable serializer
                        var nullableSerializerType = typeof(NullableSerializer <>).MakeGenericType(valueType);
                        var valueSerializerType    = typeof(IBsonSerializer <>).MakeGenericType(valueType);
                        var constructorInfo        = nullableSerializerType.GetConstructor(new[] { valueSerializerType });
                        var nullableSerializer     = (IBsonSerializer)constructorInfo.Invoke(new[] { operandTranslation.Serializer });
                        return(new AggregationExpression(expression, operandTranslation.Ast, nullableSerializer));
                    }
                }

                var ast        = AstExpression.Convert(operandTranslation.Ast, expressionType);
                var serializer = context.KnownSerializersRegistry.GetSerializer(expression);
                return(new AggregationExpression(expression, ast, serializer));
            }

            throw new ExpressionNotSupportedException(expression);
        }
Beispiel #2
0
        public static AggregationExpression Translate(TranslationContext context, NewExpression expression)
        {
            var listType     = expression.Type;
            var listItemType = listType.GetGenericArguments()[0];
            var arguments    = expression.Arguments;

            if (arguments.Count == 1)
            {
                var argument     = arguments[0];
                var argumentType = argument.Type;
                if (argumentType.IsConstructedGenericType && argumentType.GetGenericTypeDefinition() == typeof(IEnumerable <>))
                {
                    var argumentItemType = argumentType.GetGenericArguments()[0];
                    if (argumentItemType == listItemType)
                    {
                        var collectionExpression  = argument;
                        var collectionTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, collectionExpression);
                        var listSerializerType    = typeof(EnumerableInterfaceImplementerSerializer <,>).MakeGenericType(listType, listItemType);
                        var listItemSerializer    = ArraySerializerHelper.GetItemSerializer(collectionTranslation.Serializer);
                        var listSerializer        = (IBsonSerializer)Activator.CreateInstance(listSerializerType, listItemSerializer);

                        return(new AggregationExpression(expression, collectionTranslation.Ast, listSerializer));
                    }
                }
            }

            throw new ExpressionNotSupportedException(expression);
        }
        public static AggregationExpression Translate(TranslationContext context, NewExpression expression)
        {
            var constructor = expression.Constructor;
            var arguments   = expression.Arguments;

            if (constructor.IsOneOf(__dateTimeConstructors))
            {
                var yearExpression        = arguments[0];
                var monthExpression       = arguments[1];
                var dayExpression         = arguments[2];
                var hourExpression        = arguments.Count >= 4 ? arguments[3] : null;
                var minuteExpression      = arguments.Count >= 4 ? arguments[4] : null;
                var secondExpression      = arguments.Count >= 4 ? arguments[5] : null;
                var millisecondExpression = arguments.Count == 7 ? arguments[6] : null;

                var yearTranslation  = ExpressionToAggregationExpressionTranslator.Translate(context, yearExpression);
                var monthTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, monthExpression);
                var dayTranslation   = ExpressionToAggregationExpressionTranslator.Translate(context, dayExpression);
                var hourTranslation  = hourExpression != null?ExpressionToAggregationExpressionTranslator.Translate(context, hourExpression) : null;

                var minuteTranslation = minuteExpression != null?ExpressionToAggregationExpressionTranslator.Translate(context, minuteExpression) : null;

                var secondTranslation = secondExpression != null?ExpressionToAggregationExpressionTranslator.Translate(context, secondExpression) : null;

                var millisecondTranslation = millisecondExpression != null?ExpressionToAggregationExpressionTranslator.Translate(context, millisecondExpression) : null;

                var ast        = AstExpression.DateFromParts(yearTranslation.Ast, monthTranslation.Ast, dayTranslation.Ast, hourTranslation?.Ast, minuteTranslation?.Ast, secondTranslation?.Ast, millisecondTranslation?.Ast);
                var serializer = context.KnownSerializersRegistry.GetSerializer(expression);

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

            throw new ExpressionNotSupportedException(expression);
        }
        public static AggregationExpression Translate(TranslationContext context, UnaryExpression expression)
        {
            if (expression.NodeType == ExpressionType.ArrayLength)
            {
                var arrayExpression  = expression.Operand;
                var arrayTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, arrayExpression);
                var ast        = AstExpression.Size(arrayTranslation.Ast);
                var serializer = BsonSerializer.LookupSerializer(expression.Type);
                return(new AggregationExpression(expression, ast, serializer));
            }

            throw new ExpressionNotSupportedException(expression);
        }
Beispiel #5
0
        public static AggregationExpression Translate(TranslationContext context, NewArrayExpression expression)
        {
            var items = new List <AstExpression>();

            foreach (var itemExpression in expression.Expressions)
            {
                var itemTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, itemExpression);
                items.Add(itemTranslation.Ast);
            }
            var ast        = AstExpression.ComputedArray(items);
            var serializer = context.KnownSerializersRegistry.GetSerializer(expression);

            return(new AggregationExpression(expression, ast, serializer));
        }
        public static AggregationExpression Translate(TranslationContext context, UnaryExpression expression)
        {
            switch (expression.NodeType)
            {
            case ExpressionType.Convert:
                return(ConvertExpressionToAggregationExpressionTranslator.Translate(context, expression));

            case ExpressionType.Not:
                var operandTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, expression.Operand);
                var ast = AstExpression.Not(operandTranslation.Ast);
                return(new AggregationExpression(expression, ast, operandTranslation.Serializer));
            }

            throw new ExpressionNotSupportedException(expression);
        }
        public static AggregationExpression Translate(TranslationContext context, BinaryExpression expression)
        {
            if (expression.NodeType == ExpressionType.ArrayIndex)
            {
                var arrayExpression  = expression.Left;
                var arrayTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, arrayExpression);
                var indexExpression  = expression.Right;
                var indexTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, indexExpression);
                var ast            = AstExpression.ArrayElemAt(arrayTranslation.Ast, indexTranslation.Ast);
                var itemSerializer = ArraySerializerHelper.GetItemSerializer(arrayTranslation.Serializer);
                return(new AggregationExpression(expression, ast, itemSerializer));
            }

            throw new ExpressionNotSupportedException(expression);
        }
        public static AggregationExpression Translate(TranslationContext context, MemberExpression expression)
        {
            var containerExpression = expression.Expression;
            var member = expression.Member;

            if (member is PropertyInfo property)
            {
                switch (property.Name)
                {
                case "HasValue": return(HasValuePropertyToAggregationExpressionTranslator.Translate(context, expression));

                case "Value": return(ValuePropertyToAggregationExpressionTranslator.Translate(context, expression));

                default: break;
                }
            }

            var containerTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, containerExpression);

            if (containerTranslation.Serializer is IWrappedValueSerializer wrappedValueSerializer)
            {
                var unwrappedValueAst = AstExpression.GetField(containerTranslation.Ast, wrappedValueSerializer.FieldName);
                containerTranslation = new AggregationExpression(expression, unwrappedValueAst, wrappedValueSerializer.ValueSerializer);
            }

            if (!DocumentSerializerHelper.HasFieldInfo(containerTranslation.Serializer, member.Name))
            {
                if (member is PropertyInfo propertyInfo && propertyInfo.Name == "Length")
                {
                    return(LengthPropertyToAggregationExpressionTranslator.Translate(context, expression));
                }

                if (TryTranslateCollectionCountProperty(expression, containerTranslation, member, out var translatedCount))
                {
                    return(translatedCount);
                }

                if (TryTranslateDateTimeProperty(expression, containerTranslation, member, out var translatedDateTimeProperty))
                {
                    return(translatedDateTimeProperty);
                }
            }

            var fieldInfo = DocumentSerializerHelper.GetFieldInfo(containerTranslation.Serializer, member.Name);
            var ast       = AstExpression.GetField(containerTranslation.Ast, fieldInfo.ElementName);

            return(new AggregationExpression(expression, ast, fieldInfo.Serializer));
        }
Beispiel #9
0
        public static AggregationExpression Translate(TranslationContext context, ConditionalExpression expression)
        {
            if (expression.NodeType == ExpressionType.Conditional)
            {
                var testExpression     = expression.Test;
                var testTranslation    = ExpressionToAggregationExpressionTranslator.Translate(context, testExpression);
                var ifTrueExpression   = expression.IfTrue;
                var ifTrueTranslation  = ExpressionToAggregationExpressionTranslator.Translate(context, ifTrueExpression);
                var ifFalseExpression  = expression.IfFalse;
                var ifFalseTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, ifFalseExpression);
                var ast        = AstExpression.Cond(testTranslation.Ast, ifTrueTranslation.Ast, ifFalseTranslation.Ast);
                var serializer = context.KnownSerializersRegistry.GetSerializer(expression);
                return(new AggregationExpression(expression, ast, serializer));
            }

            throw new ExpressionNotSupportedException(expression);
        }
        public static AggregationExpression Translate(TranslationContext context, NewExpression expression)
        {
            if (expression.Type == typeof(DateTime))
            {
                return(NewDateTimeExpressionToAggregationExpressionTranslator.Translate(context, expression));
            }
            if (expression.Type.IsConstructedGenericType && expression.Type.GetGenericTypeDefinition() == typeof(HashSet <>))
            {
                return(NewHashSetExpressionToAggregationExpressionTranslator.Translate(context, expression));
            }
            if (expression.Type.IsConstructedGenericType && expression.Type.GetGenericTypeDefinition() == typeof(List <>))
            {
                return(NewListExpressionToAggregationExpressionTranslator.Translate(context, expression));
            }

            var classMapType   = typeof(BsonClassMap <>).MakeGenericType(expression.Type);
            var classMap       = (BsonClassMap)Activator.CreateInstance(classMapType);
            var computedFields = new List <AstComputedField>();

            for (var i = 0; i < expression.Members.Count; i++)
            {
                var member           = expression.Members[i];
                var fieldExpression  = expression.Arguments[i];
                var fieldTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, fieldExpression);
                var memberSerializer = fieldTranslation.Serializer ?? BsonSerializer.LookupSerializer(fieldExpression.Type);
                var defaultValue     = GetDefaultValue(memberSerializer.ValueType);
                classMap.MapProperty(member.Name).SetSerializer(memberSerializer).SetDefaultValue(defaultValue);
                computedFields.Add(AstExpression.ComputedField(member.Name, fieldTranslation.Ast));
            }

            var constructorInfo          = expression.Constructor;
            var constructorArgumentNames = expression.Members.Select(m => m.Name).ToArray();

            classMap.MapConstructor(constructorInfo, constructorArgumentNames);
            classMap.Freeze();

            var ast            = AstExpression.ComputedDocument(computedFields);
            var serializerType = typeof(BsonClassMapSerializer <>).MakeGenericType(expression.Type);
            // Note that we should use context.KnownSerializersRegistry to find the serializer,
            // but the above implementation builds up computedFields during the mapping process.
            // We need to figure out how to resolve the serializer from KnownSerializers and then
            // populate computedFields from that resolved serializer.
            var serializer = (IBsonSerializer)Activator.CreateInstance(serializerType, classMap);

            return(new AggregationExpression(expression, ast, serializer));
        }
Beispiel #11
0
        public static AggregationExpression Translate(TranslationContext context, MemberInitExpression expression)
        {
            var classSerializer = BsonSerializer.LookupSerializer(expression.Type);

            if (classSerializer is IBsonDocumentSerializer documentSerializer)
            {
                var computedFields = new List <AstComputedField>();

                var newExpression         = expression.NewExpression;
                var constructorParameters = newExpression.Constructor.GetParameters();
                var constructorArguments  = newExpression.Arguments;
                for (var i = 0; i < constructorParameters.Length; i++)
                {
                    var constructorParameter = constructorParameters[i];
                    var argumentExpression   = constructorArguments[i];
                    var fieldName            = GetFieldName(constructorParameter);
                    var argumentTanslation   = ExpressionToAggregationExpressionTranslator.Translate(context, argumentExpression);
                    computedFields.Add(AstExpression.ComputedField(fieldName, argumentTanslation.Ast));
                }

                foreach (var binding in expression.Bindings)
                {
                    var memberAssignment = (MemberAssignment)binding;
                    var member           = memberAssignment.Member;
                    if (!(documentSerializer.TryGetMemberSerializationInfo(member.Name, out var memberSerializationInfo)))
                    {
                        throw new ExpressionNotSupportedException(expression);
                    }
                    var elementName      = memberSerializationInfo.ElementName;
                    var valueExpression  = memberAssignment.Expression;
                    var valueTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, valueExpression);
                    computedFields.Add(AstExpression.ComputedField(elementName, valueTranslation.Ast));
                }

                var ast        = AstExpression.ComputedDocument(computedFields);
                var serializer = context.KnownSerializersRegistry.GetSerializer(expression);
                return(new AggregationExpression(expression, ast, serializer));
            }

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

            if (method.Is(StringMethod.GetChars))
            {
                var comparisonOperator  = GetComparisonOperator(expression);
                var objectExpression    = getCharsExpression.Object;
                var objectTranslation   = ExpressionToAggregationExpressionTranslator.Translate(context, objectExpression);
                var indexExpression     = arguments[0];
                var indexTranslation    = ExpressionToAggregationExpressionTranslator.Translate(context, indexExpression);
                var comparandExpression = expression.Right;
                var c         = (char)comparandExpression.GetConstantValue <int>(expression);
                var comparand = new string(c, 1);
                var ast       = AstExpression.Comparison(
                    comparisonOperator,
                    AstExpression.SubstrCP(objectTranslation.Ast, indexTranslation.Ast, 1),
                    comparand);
                return(new AggregationExpression(expression, ast, new BooleanSerializer()));
            }

            throw new ExpressionNotSupportedException(expression);
        }
        public static AggregationExpression Translate(TranslationContext context, BinaryExpression expression)
        {
            if (StringGetCharsComparisonExpressionToAggregationExpressionTranslator.CanTranslate(expression, out var getCharsExpression))
            {
                return(StringGetCharsComparisonExpressionToAggregationExpressionTranslator.Translate(context, expression, getCharsExpression));
            }

            var leftExpression  = expression.Left;
            var rightExpression = expression.Right;

            if (IsArithmeticExpression(expression))
            {
                leftExpression  = ConvertHelper.RemoveWideningConvert(leftExpression);
                rightExpression = ConvertHelper.RemoveWideningConvert(rightExpression);
            }

            if (IsEnumComparisonExpression(expression))
            {
                leftExpression  = ConvertHelper.RemoveConvertToEnumUnderlyingType(leftExpression);
                rightExpression = ConvertHelper.RemoveConvertToEnumUnderlyingType(rightExpression);
            }

            var leftTranslation  = ExpressionToAggregationExpressionTranslator.Translate(context, leftExpression);
            var rightTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, rightExpression);

            var ast = expression.NodeType switch
            {
                ExpressionType.Add => IsStringConcatenationExpression(expression) ?
                AstExpression.Concat(leftTranslation.Ast, rightTranslation.Ast) :
                AstExpression.Add(leftTranslation.Ast, rightTranslation.Ast),
                ExpressionType.And => AstExpression.And(leftTranslation.Ast, rightTranslation.Ast),
                ExpressionType.AndAlso => AstExpression.And(leftTranslation.Ast, rightTranslation.Ast),
                ExpressionType.Coalesce => AstExpression.IfNull(leftTranslation.Ast, rightTranslation.Ast),
                ExpressionType.Divide => AstExpression.Divide(leftTranslation.Ast, rightTranslation.Ast),
                ExpressionType.Equal => AstExpression.Eq(leftTranslation.Ast, rightTranslation.Ast),
                ExpressionType.GreaterThan => AstExpression.Gt(leftTranslation.Ast, rightTranslation.Ast),
                ExpressionType.GreaterThanOrEqual => AstExpression.Gte(leftTranslation.Ast, rightTranslation.Ast),
                ExpressionType.LessThan => AstExpression.Lt(leftTranslation.Ast, rightTranslation.Ast),
                ExpressionType.LessThanOrEqual => AstExpression.Lte(leftTranslation.Ast, rightTranslation.Ast),
                ExpressionType.Modulo => AstExpression.Mod(leftTranslation.Ast, rightTranslation.Ast),
                ExpressionType.Multiply => AstExpression.Multiply(leftTranslation.Ast, rightTranslation.Ast),
                ExpressionType.NotEqual => AstExpression.Ne(leftTranslation.Ast, rightTranslation.Ast),
                ExpressionType.Or => AstExpression.Or(leftTranslation.Ast, rightTranslation.Ast),
                ExpressionType.OrElse => AstExpression.Or(leftTranslation.Ast, rightTranslation.Ast),
                ExpressionType.Power => AstExpression.Pow(leftTranslation.Ast, rightTranslation.Ast),
                ExpressionType.Subtract => AstExpression.Subtract(leftTranslation.Ast, rightTranslation.Ast),
                _ => throw new ExpressionNotSupportedException(expression)
            };
            var serializer = expression.Type switch
            {
                Type t when t == typeof(bool) => new BooleanSerializer(),
                Type t when t == typeof(string) => new StringSerializer(),
                Type t when t == typeof(byte) => new ByteSerializer(),
                Type t when t == typeof(short) => new Int16Serializer(),
                Type t when t == typeof(ushort) => new UInt16Serializer(),
                Type t when t == typeof(int) => new Int32Serializer(),
                Type t when t == typeof(uint) => new UInt32Serializer(),
                Type t when t == typeof(long) => new Int64Serializer(),
                Type t when t == typeof(ulong) => new UInt64Serializer(),
                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])),
                Type
                {
                    IsArray : true
                }

                t => (IBsonSerializer)Activator.CreateInstance(typeof(ArraySerializer <>).MakeGenericType(t.GetElementType())),
                _ => context.KnownSerializersRegistry.GetSerializer(expression) // Required for Coalesce
            };

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