Represents the information needed to serialize a member.
        private Expression BuildProjector(Expression selector, ProjectionBindingContext context)
        {
            var selectorNode = selector;
            if (!(selectorNode is ISerializationExpression))
            {
                var serializer = SerializerBuilder.Build(selector, context.SerializerRegistry);
                BsonSerializationInfo info;
                switch (selector.NodeType)
                {
                    case ExpressionType.MemberInit:
                    case ExpressionType.New:
                        info = new BsonSerializationInfo(null, serializer, serializer.ValueType);
                        break;
                    default:
                        // this occurs when a computed field is used. This is a magic string
                        // that shouldn't ever be reference anywhere else...
                        info = new BsonSerializationInfo("__fld0", serializer, serializer.ValueType);
                        break;
                }

                selectorNode = new SerializationExpression(selector, info);
            }

            return selectorNode;
        }
        public override Expression Bind(ProjectionExpression projection, ProjectionBindingContext context, MethodCallExpression node, IEnumerable<Expression> arguments)
        {
            // OfType is two operations in one. First we create WhereExpression
            // for the test.  Second, we want to issue a conversion projection 
            // using the selector parameter of a ProjectionExpression such that
            // the conversion will be propogated to all future expressions.

            var newType = node.Method.GetGenericArguments()[0];

            var parameter = Expression.Parameter(projection.Projector.Type);
            var predicate = Expression.Lambda(
                Expression.TypeIs(parameter, newType),
                parameter);

            var source = BindPredicate(projection, context, projection.Source, predicate);

            var serializer = context.SerializerRegistry.GetSerializer(newType);
            var info = new BsonSerializationInfo(null, serializer, newType);

            var projector = new SerializationExpression(
                Expression.Convert(projection.Projector, newType),
                info);

            return new ProjectionExpression(
                source,
                projector);
        }
 /// <summary>
 /// Registers a serializer with the given expression.
 /// </summary>
 /// <param name="node">The expression.</param>
 /// <param name="serializer">The serializer.</param>
 public void RegisterExpressionSerializer(Expression node, IBsonSerializer serializer)
 {
     _serializationInfoCache[node] = new BsonSerializationInfo(
         null,
         serializer,
         node.Type);
 }
        /// <summary>
        /// Gets the item serialization info.
        /// </summary>
        /// <param name="methodName">Name of the method.</param>
        /// <param name="serializationInfo">The serialization info.</param>
        /// <returns>The item BsonSerializationInfo for the expression.</returns>
        public BsonSerializationInfo GetItemSerializationInfo(string methodName, BsonSerializationInfo serializationInfo)
        {
            var arraySerializer = serializationInfo.Serializer as IBsonArraySerializer;
            if (arraySerializer != null)
            {
                var itemSerializationInfo = arraySerializer.GetItemSerializationInfo();
                if (itemSerializationInfo != null)
                {
                    var arrayOptions = serializationInfo.SerializationOptions as ArraySerializationOptions;
                    if (arrayOptions != null)
                    {
                        var itemSerializationOptions = arrayOptions.ItemSerializationOptions;
                        return new BsonSerializationInfo(
                            itemSerializationInfo.ElementName,
                            itemSerializationInfo.Serializer,
                            itemSerializationInfo.NominalType,
                            itemSerializationOptions);
                    }

                    return itemSerializationInfo;
                }
            }

            string message = string.Format("{0} requires that the serializer specified for {1} support items by implementing {2} and returning a non-null result. {3} is the current serializer.",
                methodName,
                serializationInfo.ElementName,
                typeof(IBsonArraySerializer),
                serializationInfo.Serializer.GetType());
            throw new NotSupportedException(message);
        }
 /// <summary>
 /// Registers a serializer with the given expression.
 /// </summary>
 /// <param name="node">The expression.</param>
 /// <param name="serializer">The serializer.</param>
 public void RegisterExpressionSerializer(Expression node, IBsonSerializer serializer)
 {
     _serializationInfoCache[node] = new BsonSerializationInfo(
         null,
         serializer,
         node.Type,
         serializer.GetDefaultSerializationOptions());
 }
        public Expression Bind(ProjectionExpression projection, ProjectionBindingContext context, MethodCallExpression node, IEnumerable<Expression> arguments)
        {
            var distinct = new DistinctExpression(projection.Source, projection.Projector);

            var serializer = SerializerBuilder.Build(projection.Projector, context.SerializerRegistry);
            var info = new BsonSerializationInfo("_id", serializer, serializer.ValueType);
            var projector = new SerializationExpression(projection.Projector, info);

            return new ProjectionExpression(
                distinct,
                projector);
        }
        /// <summary>
        /// Gets the item serialization info.
        /// </summary>
        /// <param name="methodName">Name of the method.</param>
        /// <param name="serializationInfo">The serialization info.</param>
        /// <returns>The item BsonSerializationInfo for the expression.</returns>
        public BsonSerializationInfo GetItemSerializationInfo(string methodName, BsonSerializationInfo serializationInfo)
        {
            BsonSerializationInfo itemSerializationInfo;
            if (!TryGetItemSerializationInfo(serializationInfo, out itemSerializationInfo))
            {
                string message = string.Format("{0} requires that the serializer specified for {1} support items by implementing {2} and returning a non-null result. {3} is the current serializer.",
                    methodName,
                    serializationInfo.ElementName,
                    typeof(IBsonArraySerializer),
                    serializationInfo.Serializer.GetType());
                throw new NotSupportedException(message);
            }

            return itemSerializationInfo;
        }
        /// <summary>
        /// Tries to get the serialization info for a member.
        /// </summary>
        /// <param name="memberName">Name of the member.</param>
        /// <param name="serializationInfo">The serialization information.</param>
        /// <returns>
        ///   <c>true</c> if the serialization info exists; otherwise <c>false</c>.
        /// </returns>
        public bool TryGetMemberSerializationInfo(string memberName, out BsonSerializationInfo serializationInfo)
        {
            foreach (var memberMap in _classMap.AllMemberMaps)
            {
                if (memberMap.MemberName == memberName)
                {
                    var elementName = memberMap.ElementName;
                    var serializer  = memberMap.GetSerializer();
                    serializationInfo = new BsonSerializationInfo(elementName, serializer, serializer.ValueType);
                    return(true);
                }
            }

            serializationInfo = null;
            return(false);
        }
        /// <summary>
        /// Gets the item serialization info.
        /// </summary>
        /// <param name="methodName">Name of the method.</param>
        /// <param name="serializationInfo">The serialization info.</param>
        /// <returns>The item BsonSerializationInfo for the expression.</returns>
        public BsonSerializationInfo GetItemSerializationInfo(string methodName, BsonSerializationInfo serializationInfo)
        {
            var itemSerializationInfoProvider = serializationInfo.Serializer as IBsonItemSerializationInfoProvider;
            if (itemSerializationInfoProvider != null)
            {
                var itemSerializationInfo = itemSerializationInfoProvider.GetItemSerializationInfo();
                if (itemSerializationInfo != null)
                {
                    return itemSerializationInfo;
                }
            }

            string message = string.Format("{0} requires that the serializer specified for {1} support items by implementing {2} and returning a non-null result. {3} is the current serializer.",
                methodName,
                serializationInfo.ElementName,
                typeof(IBsonItemSerializationInfoProvider),
                serializationInfo.Serializer.GetType());
            throw new NotSupportedException(message);
        }
Example #10
0
        // protected methods
        /// <summary>
        /// Registers a member.
        /// </summary>
        /// <param name="memberName">The member name.</param>
        /// <param name="elementName">The element name.</param>
        /// <param name="serializer">The serializer.</param>
        protected void RegisterMember(string memberName, string elementName, IBsonSerializer serializer)
        {
            if (memberName == null)
            {
                throw new ArgumentNullException("memberName");
            }
            if (elementName == null)
            {
                throw new ArgumentNullException("elementName");
            }
            if (serializer == null)
            {
                throw new ArgumentNullException("serializer");
            }

            var info = new BsonSerializationInfo(elementName, serializer, serializer.ValueType);

            _memberSerializationInfo.Add(memberName, info);
        }
Example #11
0
        /// <summary>
        /// Merges the new BsonSerializationInfo by taking its properties and concatenating its ElementName.
        /// </summary>
        /// <param name="newSerializationInfo">The new info.</param>
        /// <returns>A new BsonSerializationInfo.</returns>
        public BsonSerializationInfo Merge(BsonSerializationInfo newSerializationInfo)
        {
            string elementName = null;

            if (_elementName != null && newSerializationInfo._elementName != null)
            {
                elementName = _elementName + "." + newSerializationInfo._elementName;
            }
            else if (_elementName != null)
            {
                elementName = _elementName;
            }
            else if (newSerializationInfo._elementName != null)
            {
                elementName = newSerializationInfo._elementName;
            }

            return(new BsonSerializationInfo(
                       elementName,
                       newSerializationInfo._serializer,
                       newSerializationInfo._nominalType));
        }
        // protected methods
        /// <summary>
        /// Registers a member.
        /// </summary>
        /// <param name="memberName">The member name.</param>
        /// <param name="elementName">The element name.</param>
        /// <param name="serializer">The serializer.</param>
        /// <param name="nominalType">The nominal type.</param>
        /// <param name="serializationOptions">The serialization options.</param>
        protected void RegisterMember(string memberName, string elementName, IBsonSerializer serializer, Type nominalType, IBsonSerializationOptions serializationOptions)
        {
            if (memberName == null)
            {
                throw new ArgumentNullException("memberName");
            }
            if (elementName == null)
            {
                throw new ArgumentNullException("elementName");
            }
            if (serializer == null)
            {
                throw new ArgumentNullException("serializer");
            }
            if (nominalType == null)
            {
                throw new ArgumentNullException("nominalType");
            }

            var info = new BsonSerializationInfo(elementName, serializer, nominalType, serializationOptions);

            _memberSerializationInfo.Add(memberName, info);
        }
        protected internal override Expression VisitCorrelatedGroupBy(CorrelatedGroupByExpression node)
        {
            if (_lookup != null && _lookup.Contains(node.CorrelationId))
            {
                var source = Visit(node.Source);
                var accumulators = new List<SerializationExpression>();
                var comparer = new ExpressionComparer();
                foreach (var correlatedAccumulator in _lookup[node.CorrelationId])
                {
                    var index = accumulators.FindIndex(x => comparer.Compare(x.Expression, correlatedAccumulator.Accumulator));

                    if (index == -1)
                    {
                        var serializer = _serializerRegistry.GetSerializer(correlatedAccumulator.Type);
                        var info = new BsonSerializationInfo(
                            "__agg" + accumulators.Count,
                            serializer,
                            serializer.ValueType);

                        var serializationExpression = new SerializationExpression(correlatedAccumulator.Accumulator, info);
                        accumulators.Add(serializationExpression);
                        _map[correlatedAccumulator] = serializationExpression;
                    }
                    else
                    {
                        _map[correlatedAccumulator] = accumulators[index];
                    }
                }

                node = node.Update(
                    source,
                    node.Id,
                    accumulators.OfType<Expression>());
            }

            return base.VisitCorrelatedGroupBy(node);
        }
        private Expression BindSelector(ProjectionExpression projection, ProjectionBindingContext context, Expression id, Expression node)
        {
            var lambda = ExtensionExpressionVisitor.GetLambda(node);
            var binder = new AccumulatorBinder(context.GroupMap, context.SerializerRegistry);

            var serializer = SerializerBuilder.Build(projection.Projector, context.SerializerRegistry);
            var sequenceSerializer = (IBsonSerializer)Activator.CreateInstance(
                typeof(ArraySerializer<>).MakeGenericType(projection.Projector.Type),
                new object[] { serializer });
            var sequenceInfo = new BsonSerializationInfo(
                null,
                sequenceSerializer,
                sequenceSerializer.ValueType);
            var sequenceExpression = new SerializationExpression(
                lambda.Parameters[1],
                sequenceInfo);

            binder.RegisterParameterReplacement(lambda.Parameters[0], id);
            binder.RegisterParameterReplacement(lambda.Parameters[1], sequenceExpression);
            var correlationId = Guid.NewGuid();
            context.GroupMap.Add(sequenceExpression, correlationId);
            var bound = binder.Bind(lambda.Body);
            return CorrelatedAccumulatorRemover.Remove(bound, correlationId);
        }
 public GroupIdExpression(Expression expression, BsonSerializationInfo serializationInfo)
 {
     _expression = Ensure.IsNotNull(expression, "expression");
     _serializationInfo = Ensure.IsNotNull(serializationInfo, "serializationInfo");
 }
        private BsonClassMap BuildClassMap(Type type, ProjectionMapping mapping)
        {
            if (type == null || type == typeof(object))
            {
                return null;
            }

            var baseClassMap = BuildClassMap(type.BaseType, mapping);
            if (baseClassMap != null)
            {
                baseClassMap.Freeze();
            }
            var classMap = new BsonClassMap(type, baseClassMap);

            foreach (var memberMapping in mapping.Members.Where(x => x.Member.DeclaringType == type))
            {
                var serializationExpression = memberMapping.Expression as ISerializationExpression;
                if (serializationExpression == null)
                {
                    var serializer = Build(memberMapping.Expression);
                    var serializationInfo = new BsonSerializationInfo(
                        memberMapping.Member.Name,
                        serializer,
                        GetMemberType(memberMapping.Member));
                    serializationExpression = new SerializationExpression(
                        memberMapping.Expression,
                        serializationInfo);
                }

                var memberMap = classMap.MapMember(memberMapping.Member)
                    .SetSerializer(serializationExpression.SerializationInfo.Serializer)
                    .SetElementName(memberMapping.Member.Name);

                if (classMap.IdMemberMap == null && serializationExpression is GroupIdExpression)
                {
                    classMap.SetIdMember(memberMap);
                }
            }

            return classMap;
        }
Example #17
0
 /// <summary>
 /// Tries to get the serialization info for a member.
 /// </summary>
 /// <param name="memberName">Name of the member.</param>
 /// <param name="serializationInfo">The serialization information.</param>
 /// <returns>
 ///   <c>true</c> if the serialization info exists; otherwise <c>false</c>.
 /// </returns>
 public virtual bool TryGetMemberSerializationInfo(string memberName, out BsonSerializationInfo serializationInfo)
 {
     return(_memberSerializationInfo.TryGetValue(memberName, out serializationInfo));
 }
        public void SetValue(object targetResource, string propertyName, object propertyValue)
        {
            var resourceType = GetResourceType(targetResource);
            var annotation = (TypedResourceTypeAnnotation)resourceType.CustomState;
            var memberMap = annotation.ClassMap.GetMemberMap(propertyName);
            var serializer = memberMap.GetSerializer(memberMap.MemberType) as IBsonArraySerializer;
            if (serializer != null)
            {
                var itemSerializationInfo = serializer.GetItemSerializationInfo();
                var array = itemSerializationInfo.SerializeValues((IEnumerable)propertyValue);
                var memberMapSerializationInfo = new BsonSerializationInfo(memberMap.ElementName,
                    serializer,
                    memberMap.MemberType,
                    memberMap.SerializationOptions);

                propertyValue = memberMapSerializationInfo.DeserializeValue(array);
            }
            memberMap.Setter(targetResource, propertyValue);
            if (_rememberedInstances.Contains(targetResource))
            {
                return;
            }

            var collection = GetCollection(resourceType);
            _rememberedInstances.Add(targetResource);
            _actions.Add(() => collection.Save(resourceType.InstanceType, targetResource));
        }
        /// <summary>
        /// Tries the get item serialization information.
        /// </summary>
        /// <param name="serializationInfo">The serialization information.</param>
        /// <param name="itemSerializationInfo">The item serialization information.</param>
        /// <returns></returns>
        public bool TryGetItemSerializationInfo(BsonSerializationInfo serializationInfo, out BsonSerializationInfo itemSerializationInfo)
        {
            itemSerializationInfo = null;
            var arraySerializer = serializationInfo.Serializer as IBsonArraySerializer;
            if (arraySerializer != null && arraySerializer.TryGetItemSerializationInfo(out itemSerializationInfo))
            {
                return true;
            }

            return false;
        }
        /// <summary>
        /// Merges the new BsonSerializationInfo by taking its properties and concatenating its ElementName.
        /// </summary>
        /// <param name="newSerializationInfo">The new info.</param>
        /// <returns>A new BsonSerializationInfo.</returns>
        public BsonSerializationInfo Merge(BsonSerializationInfo newSerializationInfo)
        {
            string elementName = null;
            if (_elementName != null && newSerializationInfo._elementName != null)
            {
                elementName = _elementName + "." + newSerializationInfo._elementName;
            }
            else if (_elementName != null)
            {
                elementName = _elementName;
            }
            else if (newSerializationInfo._elementName != null)
            {
                elementName = newSerializationInfo._elementName;
            }

            return new BsonSerializationInfo(
                elementName,
                newSerializationInfo._serializer,
                newSerializationInfo._nominalType);
        }
Example #21
0
        private IMongoQuery BuildContainsKeyQuery(MethodCallExpression methodCallExpression)
        {
            var dictionaryType = methodCallExpression.Object.Type;
            var dictionaryTypeInfo = dictionaryType.GetTypeInfo();
            var implementedInterfaces = new List<Type>(dictionaryTypeInfo.GetInterfaces());
            if (dictionaryTypeInfo.IsInterface)
            {
                implementedInterfaces.Add(dictionaryType);
            }

            Type dictionaryGenericInterface = null;
            Type dictionaryInterface = null;
            foreach (var implementedInterface in implementedInterfaces)
            {
                var implementedInterfaceTypeInfo = implementedInterface.GetTypeInfo();
                if (implementedInterfaceTypeInfo.IsGenericType)
                {
                    if (implementedInterfaceTypeInfo.GetGenericTypeDefinition() == typeof(IDictionary<,>))
                    {
                        dictionaryGenericInterface = implementedInterface;
                    }
                }
                else if (implementedInterface == typeof(IDictionary))
                {
                    dictionaryInterface = implementedInterface;
                }
            }

            if (dictionaryGenericInterface == null && dictionaryInterface == null)
            {
                return null;
            }

            var arguments = methodCallExpression.Arguments.ToArray();
            if (arguments.Length != 1)
            {
                return null;
            }

            var constantExpression = arguments[0] as ConstantExpression;
            if (constantExpression == null)
            {
                return null;
            }
            var key = constantExpression.Value;

            var serializationInfo = _serializationInfoHelper.GetSerializationInfo(methodCallExpression.Object);
            var serializer = serializationInfo.Serializer;

            var dictionarySerializer = serializer as IBsonDictionarySerializer;
            if (dictionarySerializer == null)
            {
                var message = string.Format(
                    "{0} in a LINQ query is only supported for members that are serialized using a serializer that implements IBsonDictionarySerializer.",
                    methodCallExpression.Method.Name); // could be Contains (for IDictionary) or ContainsKey (for IDictionary<TKey, TValue>)
                throw new NotSupportedException(message);
            }

            var keySerializer = dictionarySerializer.KeySerializer;
            var keySerializationInfo = new BsonSerializationInfo(
                null, // elementName
                keySerializer,
                keySerializer.ValueType);
            var serializedKey = _serializationInfoHelper.SerializeValue(keySerializationInfo, key);

            var dictionaryRepresentation = dictionarySerializer.DictionaryRepresentation;
            switch (dictionaryRepresentation)
            {
                case DictionaryRepresentation.ArrayOfDocuments:
                    return Query.EQ(serializationInfo.ElementName + ".k", serializedKey);
                case DictionaryRepresentation.Document:
                    return Query.Exists(serializationInfo.ElementName + "." + serializedKey.AsString);
                default:
                    var message = string.Format(
                        "{0} in a LINQ query is only supported for DictionaryRepresentation ArrayOfDocuments or Document, not {1}.",
                        methodCallExpression.Method.Name, // could be Contains (for IDictionary) or ContainsKey (for IDictionary<TKey, TValue>)
                        dictionaryRepresentation);
                    throw new NotSupportedException(message);
            }
        }
 private BsonValue SerializeValue(BsonSerializationInfo serializationInfo, object value)
 {
     var bsonDocument = new BsonDocument();
     var bsonWriter = BsonWriter.Create(bsonDocument);
     bsonWriter.WriteStartDocument();
     bsonWriter.WriteName("value");
     serializationInfo.Serializer.Serialize(bsonWriter, serializationInfo.NominalType, value, serializationInfo.SerializationOptions);
     bsonWriter.WriteEndDocument();
     return bsonDocument[0];
 }
Example #23
0
        private void TranslatePipeline(PipelineExpression node)
        {
            Translate(node.Source);

            var serializationExpression = node.Projector as ISerializationExpression;
            var fieldExpression = node.Projector as FieldExpression; // not IFieldExpression
            if (fieldExpression != null)
            {
                var info = new BsonSerializationInfo(fieldExpression.FieldName, fieldExpression.Serializer, fieldExpression.Serializer.ValueType);

                // We are projecting a field, however the server only responds
                // with documents. So we'll create a projector that reads a document
                // and then projects the field out of it.
                var parameter = Expression.Parameter(typeof(ProjectedObject), "document");
                var projector = Expression.Lambda(
                    Expression.Call(
                        parameter,
                        "GetValue",
                        new Type[] { info.Serializer.ValueType },
                        Expression.Constant(info.ElementName),
                        Expression.Constant(info.Serializer.ValueType.GetDefaultValue(), typeof(object))),
                    parameter);
                var innerSerializer = new ProjectedObjectDeserializer(new[] { info });
                _outputSerializer = (IBsonSerializer)Activator.CreateInstance(
                    typeof(ProjectingDeserializer<,>).MakeGenericType(typeof(ProjectedObject), info.Serializer.ValueType),
                    new object[]
                        {
                                innerSerializer,
                                projector.Compile()
                        });
            }
            else if (serializationExpression != null)
            {
                _outputSerializer = serializationExpression.Serializer;
            }
            else
            {
                throw new NotSupportedException();
            }

            _resultTransformer = node.ResultOperator as IResultTransformer;
        }
 /// <summary>
 /// Registers the expression serialization information.
 /// </summary>
 /// <param name="node">The node.</param>
 /// <param name="serializationInfo">The serialization information.</param>
 public void RegisterExpressionSerializationInfo(Expression node, BsonSerializationInfo serializationInfo)
 {
     _serializationInfoCache[node] = serializationInfo;
 }
 private BsonArray SerializeValues(BsonSerializationInfo serializationInfo, IEnumerable values)
 {
     var bsonDocument = new BsonDocument();
     var bsonWriter = BsonWriter.Create(bsonDocument);
     bsonWriter.WriteStartDocument();
     bsonWriter.WriteName("values");
     bsonWriter.WriteStartArray();
     foreach (var value in values)
     {
         serializationInfo.Serializer.Serialize(bsonWriter, serializationInfo.NominalType, value, serializationInfo.SerializationOptions);
     }
     bsonWriter.WriteEndArray();
     bsonWriter.WriteEndDocument();
     return bsonDocument[0].AsBsonArray;
 }
 /// <summary>
 /// Serializes the value given the serialization information.
 /// </summary>
 /// <param name="serializationInfo">The serialization info.</param>
 /// <param name="value">The value.</param>
 /// <returns>A BsonValue representing the value serialized using the serializer.</returns>
 public BsonValue SerializeValue(BsonSerializationInfo serializationInfo, object value)
 {
     return serializationInfo.SerializeValue(value);
 }
 /// <summary>
 /// Serializes the values given the serialization information.
 /// </summary>
 /// <param name="serializationInfo">The serialization info.</param>
 /// <param name="values">The values.</param>
 /// <returns>A BsonArray representing the values serialized using the serializer.</returns>
 public BsonArray SerializeValues(BsonSerializationInfo serializationInfo, IEnumerable values)
 {
     return serializationInfo.SerializeValues(values);
 }
 /// <summary>
 /// Tries the get serialization information.
 /// </summary>
 /// <param name="node">The node.</param>
 /// <param name="serializationInfo">The serialization information.</param>
 /// <returns></returns>
 public bool TryGetSerializationInfo(Expression node, out BsonSerializationInfo serializationInfo)
 {
     var evaluatedNode = PartialEvaluator.Evaluate(node);
     return BsonSerializationInfoFinder.TryGetSerializationInfo(evaluatedNode, _serializationInfoCache, out serializationInfo);
 }
        private IMongoQuery BuildContainsKeyQuery(MethodCallExpression methodCallExpression)
        {
            var dictionaryType = methodCallExpression.Object.Type;
            var implementedInterfaces = new List<Type>(dictionaryType.GetInterfaces());
            if (dictionaryType.IsInterface)
            {
                implementedInterfaces.Add(dictionaryType);
            }

            Type dictionaryGenericInterface = null;
            Type dictionaryInterface = null;
            foreach (var implementedInterface in implementedInterfaces)
            {
                if (implementedInterface.IsGenericType)
                {
                    if (implementedInterface.GetGenericTypeDefinition() == typeof(IDictionary<,>))
                    {
                        dictionaryGenericInterface = implementedInterface;
                    }
                }
                else if (implementedInterface == typeof(IDictionary))
                {
                    dictionaryInterface = implementedInterface;
                }
            }

            Type keyNominalType;
            if (dictionaryGenericInterface != null)
            {
                keyNominalType = dictionaryGenericInterface.GetGenericArguments()[0]; // TKey
            }
            else if (dictionaryInterface != null)
            {
                keyNominalType = typeof(object);
            }
            else
            {
                return null;
            }

            var arguments = methodCallExpression.Arguments.ToArray();
            if (arguments.Length != 1)
            {
                return null;
            }

            var constantExpression = arguments[0] as ConstantExpression;
            if (constantExpression == null)
            {
                return null;
            }
            var key = constantExpression.Value;

            var serializationInfo = _serializationInfoHelper.GetSerializationInfo(methodCallExpression.Object);
            var dictionarySerializationOptions = (DictionarySerializationOptions)serializationInfo.SerializationOptions ?? DictionarySerializationOptions.Defaults;

            var keyActualType = (key != null) ? key.GetType() : keyNominalType;
            var keySerializer = BsonSerializer.LookupSerializer(keyActualType);
            var keySerializationInfo = new BsonSerializationInfo(
                null, // elementName
                keySerializer,
                keyNominalType,
                dictionarySerializationOptions.KeyValuePairSerializationOptions.KeySerializationOptions);
            var serializedKey = _serializationInfoHelper.SerializeValue(keySerializationInfo, key);

            switch (dictionarySerializationOptions.Representation)
            {
                case DictionaryRepresentation.ArrayOfDocuments:
                    return Query.EQ(serializationInfo.ElementName + ".k", serializedKey);
                case DictionaryRepresentation.Document:
                    return Query.Exists(serializationInfo.ElementName + "." + serializedKey.AsString);
                default:
                    var message = string.Format(
                        "{0} in a LINQ query is only supported for DictionaryRepresentation ArrayOfDocuments or Document, not {1}.",
                        methodCallExpression.Method.Name, // could be Contains (for IDictionary) or ContainsKey (for IDictionary<TKey, TValue>)
                        dictionarySerializationOptions.Representation);
                    throw new NotSupportedException(message);
            }
        }
        private Expression BuildFromNonMethodCall(Expression node)
        {
            if (node.NodeType == ExpressionType.Constant &&
                node.Type.IsGenericType &&
                node.Type.GetGenericTypeDefinition() == typeof(IMongoQueryable<>))
            {
                var inputType = node.Type.GetGenericArguments()[0];
                var serializationInfo = new BsonSerializationInfo(
                    null,
                    _documentSerializer,
                    _documentSerializer.ValueType);

                return new ProjectionExpression(
                    new SerializationExpression(node, serializationInfo),
                    new SerializationExpression(Expression.Parameter(inputType, "document"), serializationInfo));
            }

            var message = string.Format("The expression tree is not supported: {0}",
                node.ToString());

            throw new NotSupportedException(message);
        }