/* Copyright 2010-present MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Linq.Expressions; using MongoDB.Bson; using MongoDB.Bson.Serialization; using MongoDB.Driver.Core.Misc; using MongoDB.Driver.Linq.Translators; namespace MongoDB.Driver { /// /// A rendered projection. /// /// The type of the projection. public sealed class RenderedProjectionDefinition { private readonly BsonDocument _projection; private readonly IBsonSerializer _projectionSerializer; /// /// Initializes a new instance of the class. /// /// The document. /// The projection serializer. public RenderedProjectionDefinition(BsonDocument document, IBsonSerializer projectionSerializer) { _projection = document; _projectionSerializer = Ensure.IsNotNull(projectionSerializer, nameof(projectionSerializer)); } /// /// Gets the document. /// public BsonDocument Document { get { return _projection; } } /// /// Gets the serializer. /// public IBsonSerializer ProjectionSerializer { get { return _projectionSerializer; } } } /// /// Base class for projections whose projection type is not yet known. /// /// The type of the source. public abstract class ProjectionDefinition { /// /// Renders the projection to a . /// /// The source serializer. /// The serializer registry. /// A . public abstract BsonDocument Render(IBsonSerializer sourceSerializer, IBsonSerializerRegistry serializerRegistry); /// /// Performs an implicit conversion from to . /// /// The document. /// /// The result of the conversion. /// public static implicit operator ProjectionDefinition(BsonDocument document) { if (document == null) { return null; } return new BsonDocumentProjectionDefinition(document); } /// /// Performs an implicit conversion from to . /// /// The JSON string. /// /// The result of the conversion. /// public static implicit operator ProjectionDefinition(string json) { if (json == null) { return null; } return new JsonProjectionDefinition(json); } } /// /// Base class for projections. /// /// The type of the source. /// The type of the projection. public abstract class ProjectionDefinition { /// /// Renders the projection to a . /// /// The source serializer. /// The serializer registry. /// A . public abstract RenderedProjectionDefinition Render(IBsonSerializer sourceSerializer, IBsonSerializerRegistry serializerRegistry); /// /// Performs an implicit conversion from to . /// /// The document. /// /// The result of the conversion. /// public static implicit operator ProjectionDefinition(BsonDocument document) { if (document == null) { return null; } return new BsonDocumentProjectionDefinition(document); } /// /// Performs an implicit conversion from to . /// /// The JSON string. /// /// The result of the conversion. /// public static implicit operator ProjectionDefinition(string json) { if (json == null) { return null; } return new JsonProjectionDefinition(json); } /// /// Performs an implicit conversion from to . /// /// The projection. /// /// The result of the conversion. /// public static implicit operator ProjectionDefinition(ProjectionDefinition projection) { return new KnownResultTypeProjectionDefinitionAdapter(projection); } } /// /// A based projection whose projection type is not yet known. /// /// The type of the source. public sealed class BsonDocumentProjectionDefinition : ProjectionDefinition { private readonly BsonDocument _document; /// /// Initializes a new instance of the class. /// /// The document. public BsonDocumentProjectionDefinition(BsonDocument document) { _document = Ensure.IsNotNull(document, nameof(document)); } /// /// Gets the document. /// public BsonDocument Document { get { return _document; } } /// public override BsonDocument Render(IBsonSerializer sourceSerializer, IBsonSerializerRegistry serializerRegistry) { return _document; } } /// /// A based projection. /// /// The type of the source. /// The type of the projection. public sealed class BsonDocumentProjectionDefinition : ProjectionDefinition { private readonly BsonDocument _document; private readonly IBsonSerializer _projectionSerializer; /// /// Initializes a new instance of the class. /// /// The document. /// The projection serializer. public BsonDocumentProjectionDefinition(BsonDocument document, IBsonSerializer projectionSerializer = null) { _document = Ensure.IsNotNull(document, nameof(document)); _projectionSerializer = projectionSerializer; } /// /// Gets the document. /// public BsonDocument Document { get { return _document; } } /// /// Gets the projection serializer. /// public IBsonSerializer ProjectionSerializer { get { return _projectionSerializer; } } /// public override RenderedProjectionDefinition Render(IBsonSerializer sourceSerializer, IBsonSerializerRegistry serializerRegistry) { return new RenderedProjectionDefinition( _document, _projectionSerializer ?? (sourceSerializer as IBsonSerializer) ?? serializerRegistry.GetSerializer()); } } /// /// A find based projection. /// /// The type of the source. /// The type of the projection. public sealed class FindExpressionProjectionDefinition : ProjectionDefinition { private readonly Expression> _expression; /// /// Initializes a new instance of the class. /// /// The expression. public FindExpressionProjectionDefinition(Expression> expression) { _expression = Ensure.IsNotNull(expression, nameof(expression)); } /// /// Gets the expression. /// public Expression> Expression { get { return _expression; } } /// public override RenderedProjectionDefinition Render(IBsonSerializer sourceSerializer, IBsonSerializerRegistry serializerRegistry) { return FindProjectionTranslator.Translate(_expression, sourceSerializer, serializerRegistry); } } /// /// A JSON based projection whose projection type is not yet known. /// /// The type of the source. public sealed class JsonProjectionDefinition : ProjectionDefinition { private readonly string _json; /// /// Initializes a new instance of the class. /// /// The json. public JsonProjectionDefinition(string json) { _json = Ensure.IsNotNullOrEmpty(json, nameof(json)); } /// /// Gets the json. /// public string Json { get { return _json; } } /// public override BsonDocument Render(IBsonSerializer sourceSerializer, IBsonSerializerRegistry serializerRegistry) { return BsonDocument.Parse(_json); } } /// /// A JSON based projection. /// /// The type of the source. /// The type of the projection. public sealed class JsonProjectionDefinition : ProjectionDefinition { private readonly string _json; private readonly IBsonSerializer _projectionSerializer; /// /// Initializes a new instance of the class. /// /// The json. /// The projection serializer. public JsonProjectionDefinition(string json, IBsonSerializer projectionSerializer = null) { _json = Ensure.IsNotNullOrEmpty(json, nameof(json)); _projectionSerializer = projectionSerializer; } /// /// Gets the json. /// public string Json { get { return _json; } } /// /// Gets the projection serializer. /// public IBsonSerializer ProjectionSerializer { get { return _projectionSerializer; } } /// public override RenderedProjectionDefinition Render(IBsonSerializer sourceSerializer, IBsonSerializerRegistry serializerRegistry) { return new RenderedProjectionDefinition( BsonDocument.Parse(_json), _projectionSerializer ?? (sourceSerializer as IBsonSerializer) ?? serializerRegistry.GetSerializer()); } } /// /// An based projection whose projection type is not yet known. /// /// The type of the source. public sealed class ObjectProjectionDefinition : ProjectionDefinition { private readonly object _obj; /// /// Initializes a new instance of the class. /// /// The object. public ObjectProjectionDefinition(object obj) { _obj = Ensure.IsNotNull(obj, nameof(obj)); } /// /// Gets the object. /// public object Object { get { return _obj; } } /// public override BsonDocument Render(IBsonSerializer sourceSerializer, IBsonSerializerRegistry serializerRegistry) { var serializer = serializerRegistry.GetSerializer(_obj.GetType()); return new BsonDocumentWrapper(_obj, serializer); } } /// /// An based projection. /// /// The type of the source. /// The type of the projection. public sealed class ObjectProjectionDefinition : ProjectionDefinition { private readonly object _obj; private readonly IBsonSerializer _projectionSerializer; /// /// Initializes a new instance of the class. /// /// The object. /// The projection serializer. public ObjectProjectionDefinition(object obj, IBsonSerializer projectionSerializer = null) { _obj = Ensure.IsNotNull(obj, nameof(obj)); _projectionSerializer = projectionSerializer; } /// /// Gets the object. /// public object Object { get { return _obj; } } /// /// Gets the projection serializer. /// public IBsonSerializer ProjectionSerializer { get { return _projectionSerializer; } } /// public override RenderedProjectionDefinition Render(IBsonSerializer sourceSerializer, IBsonSerializerRegistry serializerRegistry) { var serializer = serializerRegistry.GetSerializer(_obj.GetType()); return new RenderedProjectionDefinition( new BsonDocumentWrapper(_obj, serializer), _projectionSerializer ?? (sourceSerializer as IBsonSerializer) ?? serializerRegistry.GetSerializer()); } } internal sealed class KnownResultTypeProjectionDefinitionAdapter : ProjectionDefinition { private readonly ProjectionDefinition _projection; private readonly IBsonSerializer _projectionSerializer; public KnownResultTypeProjectionDefinitionAdapter(ProjectionDefinition projection, IBsonSerializer projectionSerializer = null) { _projection = Ensure.IsNotNull(projection, nameof(projection)); _projectionSerializer = projectionSerializer; } public ProjectionDefinition Projection { get { return _projection; } } public IBsonSerializer ResultSerializer { get { return _projectionSerializer; } } public override RenderedProjectionDefinition Render(IBsonSerializer sourceSerializer, IBsonSerializerRegistry serializerRegistry) { var document = _projection.Render(sourceSerializer, serializerRegistry); return new RenderedProjectionDefinition( document, _projectionSerializer ?? (sourceSerializer as IBsonSerializer) ?? serializerRegistry.GetSerializer()); } } /// /// A client side only projection that is implemented solely by deserializing using a different serializer. /// /// The type of the source. /// The type of the projection. public sealed class ClientSideDeserializationProjectionDefinition : ProjectionDefinition { private readonly IBsonSerializer _projectionSerializer; /// /// Initializes a new instance of the class. /// /// The projection serializer. public ClientSideDeserializationProjectionDefinition(IBsonSerializer projectionSerializer = null) { _projectionSerializer = projectionSerializer; } /// /// Gets the result serializer. /// /// /// The result serializer. /// public IBsonSerializer ResultSerializer { get { return _projectionSerializer; } } /// public override RenderedProjectionDefinition Render(IBsonSerializer sourceSerializer, IBsonSerializerRegistry serializerRegistry) { return new RenderedProjectionDefinition( null, _projectionSerializer ?? (sourceSerializer as IBsonSerializer) ?? serializerRegistry.GetSerializer()); } } }