public static AstFilterField Translate(TranslationContext context, MemberExpression memberExpression) { var fieldExpression = ConvertHelper.RemoveConvertToInterface(memberExpression.Expression); var field = ExpressionToFilterFieldTranslator.Translate(context, fieldExpression); var fieldSerializer = field.Serializer; var fieldSerializerType = fieldSerializer.GetType(); if (fieldSerializer is IBsonDocumentSerializer documentSerializer && documentSerializer.TryGetMemberSerializationInfo(memberExpression.Member.Name, out BsonSerializationInfo memberSerializationInfo)) { var subFieldName = memberSerializationInfo.ElementName; var subFieldSerializer = memberSerializationInfo.Serializer; return(field.SubField(subFieldName, subFieldSerializer)); } if (memberExpression.Expression.Type.IsConstructedGenericType && memberExpression.Expression.Type.GetGenericTypeDefinition() == typeof(Nullable <>) && memberExpression.Member.Name == "Value" && fieldSerializerType.IsConstructedGenericType && fieldSerializerType.GetGenericTypeDefinition() == typeof(NullableSerializer <>)) { var valueSerializer = ((IChildSerializerConfigurable)fieldSerializer).ChildSerializer; return(AstFilter.Field(field.Path, valueSerializer)); } throw new ExpressionNotSupportedException(memberExpression); }
public static AstFilter Translate(TranslationContext context, ParameterExpression expression) { if (expression.Type == typeof(bool)) { if (context.SymbolTable.TryGetSymbol(expression, out var symbol)) { var serializer = context.KnownSerializersRegistry.GetSerializer(expression); var field = AstFilter.Field(symbol.Name, serializer); return(AstFilter.Eq(field, true)); } } throw new ExpressionNotSupportedException(expression); }
// public static methods public static ExecutableQuery <TDocument, bool> Translate <TDocument>(MongoQueryProvider <TDocument> provider, TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.Is(QueryableMethod.Contains)) { var sourceExpression = arguments[0]; var pipeline = ExpressionToPipelineTranslator.Translate(context, sourceExpression); IBsonSerializer valueSerializer; if (pipeline.OutputSerializer is IWrappedValueSerializer wrappedValueSerializer) { valueSerializer = wrappedValueSerializer.ValueSerializer; } else { valueSerializer = pipeline.OutputSerializer; wrappedValueSerializer = WrappedValueSerializer.Create("_v", valueSerializer); pipeline = pipeline.AddStages( wrappedValueSerializer, AstStage.Project( AstProject.ExcludeId(), AstProject.Set("_v", AstExpression.Var("ROOT")))); } var itemExpression = arguments[1]; var itemValue = itemExpression.GetConstantValue <object>(containingExpression: expression); var serializedValue = SerializationHelper.SerializeValue(pipeline.OutputSerializer, itemValue); AstFilter filter = AstFilter.Eq(AstFilter.Field("_v", valueSerializer), serializedValue); pipeline = pipeline.AddStages( __outputSerializer, AstStage.Match(filter), AstStage.Limit(1), AstStage.Project( AstProject.ExcludeId(), AstProject.Set("_v", BsonNull.Value))); return(ExecutableQuery.Create( provider.Collection, provider.Options, pipeline, __finalizer)); } throw new ExpressionNotSupportedException(expression); }
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); }
private static AstFilter Translate(TranslationContext context, Expression expression, Expression sourceExpression, Expression itemExpression) { if (itemExpression.NodeType == ExpressionType.Constant) { var sourceField = ExpressionToFilterFieldTranslator.Translate(context, sourceExpression); var itemSerializer = ArraySerializerHelper.GetItemSerializer(sourceField.Serializer); var value = itemExpression.GetConstantValue <object>(containingExpression: expression); var serializedValue = SerializationHelper.SerializeValue(itemSerializer, value); return(AstFilter.ElemMatch(sourceField, AstFilter.Eq(AstFilter.Field("@<elem>", itemSerializer), serializedValue))); // @<elem> represents the implied element } var itemField = ExpressionToFilterFieldTranslator.Translate(context, itemExpression); var sourceValues = sourceExpression.GetConstantValue <IEnumerable>(containingExpression: expression); var serializedValues = SerializationHelper.SerializeValues(itemField.Serializer, sourceValues); return(AstFilter.In(itemField, serializedValues)); }
public override AstNode VisitFilterField(AstFilterField node) { // "_elements.0.X" => { __agg0 : { $first : "$$ROOT" } } + "__agg0.X" if (node.Path.StartsWith("_elements.0.")) { var accumulatorExpression = AstExpression.AccumulatorExpression(AstAccumulatorOperator.First, AstExpression.Var("ROOT")); var accumulatorFieldName = _accumulators.AddAccumulatorExpression(accumulatorExpression); var restOfPath = node.Path.Substring("_elements.0.".Length); var rewrittenPath = $"{accumulatorFieldName}.{restOfPath}"; return(AstFilter.Field(rewrittenPath, node.Serializer)); } if (node.Path == "_elements" || node.Path.StartsWith("_elements.")) { throw new UnableToRemoveReferenceToElementsException(); } return(base.VisitFilterField(node)); }
public static AstFilterField Translate(TranslationContext context, ParameterExpression expression) { var symbolTable = context.SymbolTable; if (symbolTable.TryGetSymbol(expression, out Symbol symbol)) { var fieldName = symbol.IsCurrent ? "@<current>" : symbol.Name; var fieldSerializer = symbol.Serializer; var field = AstFilter.Field(fieldName, fieldSerializer); if (fieldSerializer is IWrappedValueSerializer wrappedValueSerializer) { field = field.SubField("_v", wrappedValueSerializer.ValueSerializer); } return(field); } throw new ExpressionNotSupportedException(expression); }
// public static methods public static AstPipeline Translate(TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.Is(QueryableMethod.OfType)) { var sourceExpression = arguments[0]; var pipeline = ExpressionToPipelineTranslator.Translate(context, sourceExpression); var sourceType = sourceExpression.Type; var nominalType = sourceType.GetGenericArguments()[0]; var actualType = method.GetGenericArguments()[0]; var discriminatorConvention = BsonSerializer.LookupDiscriminatorConvention(nominalType); var discriminatorElementName = discriminatorConvention.ElementName; var wrappedValueOutputSerializer = pipeline.OutputSerializer as IWrappedValueSerializer; if (wrappedValueOutputSerializer != null) { discriminatorElementName = wrappedValueOutputSerializer.FieldName + "." + discriminatorElementName; } var discriminatorField = AstFilter.Field(discriminatorElementName, BsonValueSerializer.Instance); var discriminatorValue = discriminatorConvention.GetDiscriminator(nominalType, actualType); var filter = AstFilter.Eq(discriminatorField, discriminatorValue); // note: OfType only works with hierarchical discriminators var actualSerializer = context.KnownSerializersRegistry.GetSerializer(expression); if (wrappedValueOutputSerializer != null) { actualSerializer = WrappedValueSerializer.Create(wrappedValueOutputSerializer.FieldName, actualSerializer); } pipeline = pipeline.AddStages( actualSerializer, AstStage.Match(filter)); return(pipeline); } throw new ExpressionNotSupportedException(expression); }
public static AstFilterField Translate(TranslationContext context, UnaryExpression expression) { if (expression.NodeType == ExpressionType.Convert) { var field = ExpressionToFilterFieldTranslator.Translate(context, expression.Operand); var fieldSerializer = field.Serializer; var fieldType = fieldSerializer.ValueType; var targetType = expression.Type; if (fieldType.IsEnum()) { var enumType = fieldType; var enumUnderlyingType = enumType.GetEnumUnderlyingType(); if (targetType == enumUnderlyingType) { var enumUnderlyingTypeSerializer = EnumUnderlyingTypeSerializer.Create(fieldSerializer); return(AstFilter.Field(field.Path, enumUnderlyingTypeSerializer)); } } if (IsNumericType(targetType)) { IBsonSerializer targetTypeSerializer = expression.Type switch { 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(), _ => throw new ExpressionNotSupportedException(expression) }; if (fieldSerializer is IRepresentationConfigurable representationConfigurableFieldSerializer && targetTypeSerializer is IRepresentationConfigurable representationConfigurableTargetTypeSerializer) { var fieldRepresentation = representationConfigurableFieldSerializer.Representation; if (fieldRepresentation == BsonType.String) { targetTypeSerializer = representationConfigurableTargetTypeSerializer.WithRepresentation(fieldRepresentation); } } if (fieldSerializer is IRepresentationConverterConfigurable converterConfigurableFieldSerializer && targetTypeSerializer is IRepresentationConverterConfigurable converterConfigurableTargetTypeSerializer) { targetTypeSerializer = converterConfigurableTargetTypeSerializer.WithConverter(converterConfigurableFieldSerializer.Converter); } return(AstFilter.Field(field.Path, targetTypeSerializer)); } if (targetType.IsConstructedGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable <>)) { var nullableValueType = targetType.GetGenericArguments()[0]; if (nullableValueType == fieldType) { var nullableSerializerType = typeof(NullableSerializer <>).MakeGenericType(nullableValueType); var nullableSerializer = (IBsonSerializer)Activator.CreateInstance(nullableSerializerType, fieldSerializer); return(AstFilter.Field(field.Path, nullableSerializer)); } if (fieldType.IsConstructedGenericType && fieldType.GetGenericTypeDefinition() == typeof(Nullable <>)) { var fieldValueType = fieldType.GetGenericArguments()[0]; if (fieldValueType.IsEnum()) { var enumUnderlyingType = fieldValueType.GetEnumUnderlyingType(); if (nullableValueType == enumUnderlyingType) { var fieldSerializerType = fieldSerializer.GetType(); if (fieldSerializerType.IsConstructedGenericType && fieldSerializerType.GetGenericTypeDefinition() == typeof(NullableSerializer <>)) { var enumSerializer = ((IChildSerializerConfigurable)fieldSerializer).ChildSerializer; var enumUnderlyingTypeSerializer = EnumUnderlyingTypeSerializer.Create(enumSerializer); var nullableSerializerType = typeof(NullableSerializer <>).MakeGenericType(nullableValueType); var nullableSerializer = (IBsonSerializer)Activator.CreateInstance(nullableSerializerType, enumUnderlyingTypeSerializer); return(AstFilter.Field(field.Path, nullableSerializer)); } } } } } } throw new ExpressionNotSupportedException(expression); }