/* 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 MongoDB.Bson; using MongoDB.Bson.IO; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Serializers; namespace MongoDB.Driver { /// /// Represents a DBRef (a convenient way to refer to a document). /// [BsonSerializer(typeof(MongoDBRefSerializer))] public class MongoDBRef : IEquatable { // private fields private string _databaseName; private string _collectionName; private BsonValue _id; // constructors // default constructor is private and only used for deserialization private MongoDBRef() { } /// /// Creates a MongoDBRef. /// /// The name of the collection that contains the document. /// The Id of the document. public MongoDBRef(string collectionName, BsonValue id) : this(null, collectionName, id) { } /// /// Creates a MongoDBRef. /// /// The name of the database that contains the document. /// The name of the collection that contains the document. /// The Id of the document. public MongoDBRef(string databaseName, string collectionName, BsonValue id) { if (collectionName == null) { throw new ArgumentNullException("collectionName"); } if (id == null) { throw new ArgumentNullException("id"); } _databaseName = databaseName; _collectionName = collectionName; _id = id; } // public properties /// /// Gets the name of the database that contains the document. /// public string DatabaseName { get { return _databaseName; } } /// /// Gets the name of the collection that contains the document. /// public string CollectionName { get { return _collectionName; } } /// /// Gets the Id of the document. /// public BsonValue Id { get { return _id; } } // public operators /// /// Determines whether two specified MongoDBRef objects have different values. /// /// The first value to compare, or null. /// The second value to compare, or null. /// True if the value of lhs is different from the value of rhs; otherwise, false. public static bool operator !=(MongoDBRef lhs, MongoDBRef rhs) { return !MongoDBRef.Equals(lhs, rhs); } /// /// Determines whether two specified MongoDBRef objects have the same value. /// /// The first value to compare, or null. /// The second value to compare, or null. /// True if the value of lhs is the same as the value of rhs; otherwise, false. public static bool operator ==(MongoDBRef lhs, MongoDBRef rhs) { return MongoDBRef.Equals(lhs, rhs); } // public static methods /// /// Determines whether two specified MongoDBRef objects have the same value. /// /// The first value to compare, or null. /// The second value to compare, or null. /// True if the value of lhs is the same as the value of rhs; otherwise, false. public static bool Equals(MongoDBRef lhs, MongoDBRef rhs) { if ((object)lhs == null) { return (object)rhs == null; } return lhs.Equals(rhs); } // public methods /// /// Determines whether this instance and another specified MongoDBRef object have the same value. /// /// The MongoDBRef object to compare to this instance. /// True if the value of the rhs parameter is the same as this instance; otherwise, false. public bool Equals(MongoDBRef rhs) { if ((object)rhs == null || GetType() != rhs.GetType()) { return false; } if ((object)this == (object)rhs) { return true; } // note: _databaseName can be null return string.Equals(_databaseName, rhs._databaseName) && _collectionName.Equals(rhs._collectionName) && _id.Equals(rhs._id); } /// /// Determines whether this instance and a specified object, which must also be a MongoDBRef object, have the same value. /// /// The MongoDBRef object to compare to this instance. /// True if obj is a MongoDBRef object and its value is the same as this instance; otherwise, false. public override bool Equals(object obj) { return Equals(obj as MongoDBRef); // works even if obj is null or of a different type } /// /// Returns the hash code for this MongoDBRef object. /// /// A 32-bit signed integer hash code. public override int GetHashCode() { // see Effective Java by Joshua Bloch int hash = 17; hash = 37 * hash + ((_databaseName == null) ? 0 : _databaseName.GetHashCode()); hash = 37 * hash + _collectionName.GetHashCode(); hash = 37 * hash + _id.GetHashCode(); return hash; } /// /// Returns a string representation of the value. /// /// A string representation of the value. public override string ToString() { if (_databaseName == null) { return string.Format("new MongoDBRef(\"{0}\", {1})", _collectionName, _id); } else { return string.Format("new MongoDBRef(\"{0}\", \"{1}\", {2})", _databaseName, _collectionName, _id); } } } /// /// Represents a serializer for MongoDBRefs. /// public class MongoDBRefSerializer : ClassSerializerBase, IBsonDocumentSerializer { // private constants private static class Flags { public const long CollectionName = 1; public const long Id = 2; public const long DatabaseName = 4; } // private fields private readonly SerializerHelper _helper; // constructors /// /// Initializes a new instance of the class. /// public MongoDBRefSerializer() { _helper = new SerializerHelper ( new SerializerHelper.Member("$ref", Flags.CollectionName), new SerializerHelper.Member("$id", Flags.Id), new SerializerHelper.Member("$db", Flags.DatabaseName, isOptional: true) ); } // public methods /// /// 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) { string elementName; IBsonSerializer serializer; switch (memberName) { case "DatabaseName": elementName = "$db"; serializer = new StringSerializer(); break; case "CollectionName": elementName = "$ref"; serializer = new StringSerializer(); break; case "Id": elementName = "$id"; serializer = BsonValueSerializer.Instance; break; default: serializationInfo = null; return false; } serializationInfo = new BsonSerializationInfo(elementName, serializer, serializer.ValueType); return true; } // protected methods /// /// Deserializes a value. /// /// The deserialization context. /// The deserialization args. /// The value. protected override MongoDBRef DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args) { var bsonReader = context.Reader; string databaseName = null; string collectionName = null; BsonValue id = null; _helper.DeserializeMembers(context, (elementName, flag) => { switch (flag) { case Flags.CollectionName: collectionName = bsonReader.ReadString(); break; case Flags.Id: id = BsonValueSerializer.Instance.Deserialize(context); break; case Flags.DatabaseName: databaseName = bsonReader.ReadString(); break; } }); return new MongoDBRef(databaseName, collectionName, id); } /// /// Serializes a value. /// /// The serialization context. /// The serialization args. /// The value. protected override void SerializeValue(BsonSerializationContext context, BsonSerializationArgs args, MongoDBRef value) { var bsonWriter = context.Writer; bsonWriter.WriteStartDocument(); bsonWriter.WriteString("$ref", value.CollectionName); bsonWriter.WriteName("$id"); BsonValueSerializer.Instance.Serialize(context, value.Id); if (value.DatabaseName != null) { bsonWriter.WriteString("$db", value.DatabaseName); } bsonWriter.WriteEndDocument(); } } }