Пример #1
0
        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);
        }
Пример #2
0
        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);
        }
Пример #4
0
        public static (AstFilterField, AstFilter) Translate(TranslationContext context, Expression sourceExpression)
        {
            if (sourceExpression is MethodCallExpression sourceMethodCallExpression)
            {
                var method    = sourceMethodCallExpression.Method;
                var arguments = sourceMethodCallExpression.Arguments;

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

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

                    return(actualTypeSourceField, combinedFilter);
                }

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

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

                    return(sourceField, combinedFilter);
                }
            }

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

            return(field, null);
        }
Пример #5
0
        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));
        }
Пример #6
0
            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);
        }
Пример #8
0
        // 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);
        }