public static RenderedProjectionDefinition <TProjection> Translate <TDocument, TProjection>(Expression <Func <TDocument, TProjection> > projector, IBsonSerializer <TDocument> parameterSerializer, IBsonSerializerRegistry serializerRegistry) { var bindingContext = new PipelineBindingContext(serializerRegistry); var documentExpression = new DocumentExpression(parameterSerializer); bindingContext.AddExpressionMapping(projector.Parameters[0], documentExpression); var node = PartialEvaluator.Evaluate(projector.Body); node = Transformer.Transform(node); node = bindingContext.Bind(node, isClientSideProjection: true); node = FieldExpressionFlattener.FlattenFields(node); BsonDocument projectionDocument = null; IBsonSerializer <TProjection> serializer; if (node is DocumentExpression) { serializer = new ProjectingDeserializer <TDocument, TProjection>(parameterSerializer, projector.Compile()); } else { var candidateFields = SerializationExpressionGatherer.Gather(node); var fields = GetUniqueFieldsByHierarchy(candidateFields); var serializationInfo = fields.Select(x => new BsonSerializationInfo(x.FieldName, x.Serializer, x.Serializer.ValueType)).ToList(); var projectedObjectExpression = Expression.Parameter(typeof(ProjectedObject), "document"); var translator = new FindProjectionTranslator(documentExpression, projectedObjectExpression, fields); var translated = translator.Visit(node); if (translator._fullDocument) { serializer = new ProjectingDeserializer <TDocument, TProjection>(parameterSerializer, projector.Compile()); } else { var newProjector = Expression.Lambda <Func <ProjectedObject, TProjection> >( translated, projectedObjectExpression); projectionDocument = GetProjectionDocument(serializationInfo); var projectedObjectSerializer = new ProjectedObjectDeserializer(serializationInfo); serializer = new ProjectingDeserializer <ProjectedObject, TProjection>(projectedObjectSerializer, newProjector.Compile()); } } return(new RenderedProjectionDefinition <TProjection>(projectionDocument, serializer)); }
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; }