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); }
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); }
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)); }
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)); }
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)); }