/* 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.Collections.Generic;
using System.Linq;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization.IdGenerators;
namespace MongoDB.Bson.Serialization.Serializers
{
///
/// Represents a serializer for BsonDocuments.
///
public class BsonDocumentSerializer : BsonValueSerializerBase, IBsonDocumentSerializer, IBsonIdProvider
{
// private static fields
private static BsonDocumentSerializer __instance = new BsonDocumentSerializer();
// constructors
///
/// Initializes a new instance of the BsonDocumentSerializer class.
///
public BsonDocumentSerializer()
: base(BsonType.Document)
{
}
// public static properties
///
/// Gets an instance of the BsonDocumentSerializer class.
///
public static BsonDocumentSerializer Instance
{
get { return __instance; }
}
// public methods
///
/// Deserializes a value.
///
/// The deserialization context.
/// The deserialization args.
/// A deserialized value.
protected override BsonDocument DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var bsonReader = context.Reader;
bsonReader.ReadStartDocument();
var document = new BsonDocument(allowDuplicateNames: context.AllowDuplicateElementNames);
while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
{
var name = bsonReader.ReadName();
var value = BsonValueSerializer.Instance.Deserialize(context);
document.Add(name, value);
}
bsonReader.ReadEndDocument();
return document;
}
///
/// Gets the document Id.
///
/// The document.
/// The Id.
/// The nominal type of the Id.
/// The IdGenerator for the Id type.
/// True if the document has an Id.
public bool GetDocumentId(
object document,
out object id,
out Type idNominalType,
out IIdGenerator idGenerator)
{
var bsonDocument = (BsonDocument)document;
BsonValue idBsonValue;
if (bsonDocument.TryGetValue("_id", out idBsonValue))
{
id = idBsonValue;
idGenerator = BsonSerializer.LookupIdGenerator(id.GetType());
if (idGenerator == null)
{
var idBinaryData = id as BsonBinaryData;
if (idBinaryData != null && (idBinaryData.SubType == BsonBinarySubType.UuidLegacy || idBinaryData.SubType == BsonBinarySubType.UuidStandard))
{
idGenerator = BsonBinaryDataGuidGenerator.GetInstance(idBinaryData.GuidRepresentation);
}
}
}
else
{
id = null;
idGenerator = BsonObjectIdGenerator.Instance;
}
idNominalType = typeof(BsonValue);
return true;
}
///
/// Tries to get the serialization info for a member.
///
/// Name of the member.
/// The serialization information.
///
/// true if the serialization info exists; otherwise false.
///
public bool TryGetMemberSerializationInfo(string memberName, out BsonSerializationInfo serializationInfo)
{
serializationInfo = new BsonSerializationInfo(
memberName,
BsonValueSerializer.Instance,
typeof(BsonValue));
return true;
}
///
/// Serializes a value.
///
/// The serialization context.
/// The serialization args.
/// The object.
protected override void SerializeValue(BsonSerializationContext context, BsonSerializationArgs args, BsonDocument value)
{
var bsonWriter = context.Writer;
bsonWriter.WriteStartDocument();
var alreadySerializedIndex = -1;
if (args.SerializeIdFirst)
{
var idIndex = value.IndexOfName("_id");
if (idIndex != -1)
{
bsonWriter.WriteName("_id");
BsonValueSerializer.Instance.Serialize(context, value[idIndex]);
alreadySerializedIndex = idIndex;
}
}
var elementCount = value.ElementCount;
for (var index = 0; index < elementCount; index++)
{
if (index == alreadySerializedIndex)
{
continue;
}
var element = value.GetElement(index);
bsonWriter.WriteName(element.Name);
BsonValueSerializer.Instance.Serialize(context, element.Value);
}
bsonWriter.WriteEndDocument();
}
///
/// Sets the document Id.
///
/// The document.
/// The Id.
public void SetDocumentId(object document, object id)
{
if (document == null)
{
throw new ArgumentNullException("document");
}
if (id == null)
{
throw new ArgumentNullException("id");
}
var bsonDocument = (BsonDocument)document;
var idBsonValue = id as BsonValue;
if (idBsonValue == null)
{
idBsonValue = BsonValue.Create(id); // be helpful and provide automatic conversion to BsonValue if necessary
}
var idIndex = bsonDocument.IndexOfName("_id");
if (idIndex != -1)
{
bsonDocument[idIndex] = idBsonValue;
}
else
{
bsonDocument.InsertAt(0, new BsonElement("_id", idBsonValue));
}
}
}
}