diff --git a/Bson/Serialization/Conventions/ConventionProfile.cs b/Bson/Serialization/Conventions/ConventionProfile.cs index e4b9be4b381..99f501c9507 100644 --- a/Bson/Serialization/Conventions/ConventionProfile.cs +++ b/Bson/Serialization/Conventions/ConventionProfile.cs @@ -1,297 +1,297 @@ -/* Copyright 2010-2012 10gen 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 System.Text; - -namespace MongoDB.Bson.Serialization.Conventions -{ - /// - /// Represents a set of conventions. - /// - public sealed class ConventionProfile - { - // public properties - /// - /// Gets the default value convention. - /// - public IDefaultValueConvention DefaultValueConvention { get; private set; } - - /// - /// Gets the element name convention. - /// - public IElementNameConvention ElementNameConvention { get; private set; } - - /// - /// Gets the extra elements member convention. - /// - public IExtraElementsMemberConvention ExtraElementsMemberConvention { get; private set; } - - /// - /// Gets the Id generator convention. - /// - public IIdGeneratorConvention IdGeneratorConvention { get; private set; } - - /// - /// Gets the Id member convention. - /// - public IIdMemberConvention IdMemberConvention { get; private set; } - - /// - /// Gets the ignore extra elements convention. - /// - public IIgnoreExtraElementsConvention IgnoreExtraElementsConvention { get; private set; } - - /// - /// Gets the ignore if default convention. - /// - public IIgnoreIfDefaultConvention IgnoreIfDefaultConvention { get; private set; } - - /// - /// Gets the ignore if null convention. - /// - public IIgnoreIfNullConvention IgnoreIfNullConvention { get; private set; } - - /// - /// Gets the member finder convention. - /// - public IMemberFinderConvention MemberFinderConvention { get; private set; } - - /// - /// Gets the BSON serialization options convention. - /// - public ISerializationOptionsConvention SerializationOptionsConvention { get; private set; } - - /// - /// Gets the default value convention. - /// - [Obsolete("SerializeDefaultValueConvention is obsolete and will be removed in a future version of the C# driver. Please use IgnoreIfDefaultConvention instead.")] - public ISerializeDefaultValueConvention SerializeDefaultValueConvention { get; private set; } - - // public static methods - /// - /// Gets the default convention profile. - /// - /// The default convention profile. - public static ConventionProfile GetDefault() - { - return new ConventionProfile() // The default profile always matches... - .SetDefaultValueConvention(new NullDefaultValueConvention()) - .SetElementNameConvention(new MemberNameElementNameConvention()) - .SetExtraElementsMemberConvention(new NamedExtraElementsMemberConvention("ExtraElements")) - .SetIdGeneratorConvention(new LookupIdGeneratorConvention()) - .SetIdMemberConvention(new NamedIdMemberConvention("Id", "id", "_id")) - .SetIgnoreExtraElementsConvention(new NeverIgnoreExtraElementsConvention()) - .SetIgnoreIfDefaultConvention(new NeverIgnoreIfDefaultConvention()) - .SetIgnoreIfNullConvention(new NeverIgnoreIfNullConvention()) - .SetMemberFinderConvention(new PublicMemberFinderConvention()) - .SetSerializationOptionsConvention(new NullSerializationOptionsConvention()); - } - - // public methods - /// - /// Merges another convention profile into this one (only missing conventions are merged). - /// - /// The other convention profile. - public void Merge(ConventionProfile other) - { - if (DefaultValueConvention == null) - { - DefaultValueConvention = other.DefaultValueConvention; - } - if (ElementNameConvention == null) - { - ElementNameConvention = other.ElementNameConvention; - } - if (ExtraElementsMemberConvention == null) - { - ExtraElementsMemberConvention = other.ExtraElementsMemberConvention; - } - if (IdGeneratorConvention == null) - { - IdGeneratorConvention = other.IdGeneratorConvention; - } - if (IdMemberConvention == null) - { - IdMemberConvention = other.IdMemberConvention; - } - if (IgnoreExtraElementsConvention == null) - { - IgnoreExtraElementsConvention = other.IgnoreExtraElementsConvention; - } -#pragma warning disable 618 // SerializeDefaultValueConvention is obsolete - if (IgnoreIfDefaultConvention == null && SerializeDefaultValueConvention == null) - { - if (other.SerializeDefaultValueConvention != null) - { - SerializeDefaultValueConvention = other.SerializeDefaultValueConvention; - } - else - { - IgnoreIfDefaultConvention = other.IgnoreIfDefaultConvention; - } - } -#pragma warning restore 618 - if (IgnoreIfNullConvention == null) - { - IgnoreIfNullConvention = other.IgnoreIfNullConvention; - } - if (MemberFinderConvention == null) - { - MemberFinderConvention = other.MemberFinderConvention; - } - if (SerializationOptionsConvention == null) - { - SerializationOptionsConvention = other.SerializationOptionsConvention; - } - } - - /// - /// Sets the default value convention. - /// - /// A default value convention. - /// The convention profile. - public ConventionProfile SetDefaultValueConvention(IDefaultValueConvention convention) - { - DefaultValueConvention = convention; - return this; - } - - /// - /// Sets the element name convention. - /// - /// An element name convention. - /// The convention profile. - public ConventionProfile SetElementNameConvention(IElementNameConvention convention) - { - ElementNameConvention = convention; - return this; - } - - /// - /// Sets the extra elements member convention. - /// - /// An extra elements member convention. - /// The convention profile. - public ConventionProfile SetExtraElementsMemberConvention(IExtraElementsMemberConvention convention) - { - ExtraElementsMemberConvention = convention; - return this; - } - - /// - /// Sets the Id generator convention. - /// - /// An Id generator convention. - /// The convention profile. - public ConventionProfile SetIdGeneratorConvention(IIdGeneratorConvention convention) - { - IdGeneratorConvention = convention; - return this; - } - - /// - /// Sets the Id member convention. - /// - /// An Id member convention. - /// The convention profile. - public ConventionProfile SetIdMemberConvention(IIdMemberConvention convention) - { - IdMemberConvention = convention; - return this; - } - - /// - /// Sets the ignore extra elements convention. - /// - /// An ignore extra elements convention. - /// The convention profile. - public ConventionProfile SetIgnoreExtraElementsConvention(IIgnoreExtraElementsConvention convention) - { - IgnoreExtraElementsConvention = convention; - return this; - } - - /// - /// Sets the ignore if default convention. - /// - /// An ignore if default convention. - /// The convention profile. - public ConventionProfile SetIgnoreIfDefaultConvention(IIgnoreIfDefaultConvention convention) - { -#pragma warning disable 618 // SerializeDefaultValueConvention is obsolete - if (convention != null && SerializeDefaultValueConvention != null) - { - throw new InvalidOperationException("IgnoreIfDefaultConvention cannot be set because SerializeDefaultValueConvention is set."); - } -#pragma warning restore 618 - IgnoreIfDefaultConvention = convention; - return this; - } - - /// - /// Sets the ignore if null convention. - /// - /// An ignore if null convention. - /// The convention profile. - public ConventionProfile SetIgnoreIfNullConvention(IIgnoreIfNullConvention convention) - { - IgnoreIfNullConvention = convention; - return this; - } - - /// - /// Sets the member finder convention. - /// - /// A member finder convention. - /// The convention profile. - public ConventionProfile SetMemberFinderConvention(IMemberFinderConvention convention) - { - MemberFinderConvention = convention; - return this; - } - - /// - /// Sets the serialization options convention. - /// - /// A serialization options convention. - /// The convention profile. - public ConventionProfile SetSerializationOptionsConvention(ISerializationOptionsConvention convention) - { - SerializationOptionsConvention = convention; - return this; - } - - /// - /// Sets the serialize default value convention. - /// - /// A serialize default value convention. - /// The convention profile. - [Obsolete("SetSerializeDefaultValueConvention is obsolete and will be removed in a future version of the C# driver. Please use SetIgnoreIfDefaultConvention instead.")] - public ConventionProfile SetSerializeDefaultValueConvention(ISerializeDefaultValueConvention convention) - { - if (convention != null && IgnoreIfDefaultConvention != null) - { - throw new InvalidOperationException("SerializeDefaultValueConvention cannot be set because IgnoreIfDefaultConvention is set."); - } -#pragma warning disable 618 // SerializeDefaultValueConvention is obsolete - SerializeDefaultValueConvention = convention; -#pragma warning restore 618 - return this; - } - } -} +/* Copyright 2010-2012 10gen 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 System.Text; + +namespace MongoDB.Bson.Serialization.Conventions +{ + /// + /// Represents a set of conventions. + /// + public sealed class ConventionProfile + { + // public properties + /// + /// Gets the default value convention. + /// + public IDefaultValueConvention DefaultValueConvention { get; private set; } + + /// + /// Gets the element name convention. + /// + public IElementNameConvention ElementNameConvention { get; private set; } + + /// + /// Gets the extra elements member convention. + /// + public IExtraElementsMemberConvention ExtraElementsMemberConvention { get; private set; } + + /// + /// Gets the Id generator convention. + /// + public IIdGeneratorConvention IdGeneratorConvention { get; private set; } + + /// + /// Gets the Id member convention. + /// + public IIdMemberConvention IdMemberConvention { get; private set; } + + /// + /// Gets the ignore extra elements convention. + /// + public IIgnoreExtraElementsConvention IgnoreExtraElementsConvention { get; private set; } + + /// + /// Gets the ignore if default convention. + /// + public IIgnoreIfDefaultConvention IgnoreIfDefaultConvention { get; private set; } + + /// + /// Gets the ignore if null convention. + /// + public IIgnoreIfNullConvention IgnoreIfNullConvention { get; private set; } + + /// + /// Gets the member finder convention. + /// + public IMemberFinderConvention MemberFinderConvention { get; private set; } + + /// + /// Gets the BSON serialization options convention. + /// + public ISerializationOptionsConvention SerializationOptionsConvention { get; private set; } + + /// + /// Gets the default value convention. + /// + [Obsolete("SerializeDefaultValueConvention is obsolete and will be removed in a future version of the C# driver. Please use IgnoreIfDefaultConvention instead.")] + public ISerializeDefaultValueConvention SerializeDefaultValueConvention { get; private set; } + + // public static methods + /// + /// Gets the default convention profile. + /// + /// The default convention profile. + public static ConventionProfile GetDefault() + { + return new ConventionProfile() // The default profile always matches... + .SetDefaultValueConvention(new NullDefaultValueConvention()) + .SetElementNameConvention(new MemberNameElementNameConvention()) + .SetExtraElementsMemberConvention(new NamedExtraElementsMemberConvention("ExtraElements")) + .SetIdGeneratorConvention(new LookupIdGeneratorConvention()) + .SetIdMemberConvention(new NamedIdMemberConvention("Id", "id", "_id")) + .SetIgnoreExtraElementsConvention(new NeverIgnoreExtraElementsConvention()) + .SetIgnoreIfDefaultConvention(new NeverIgnoreIfDefaultConvention()) + .SetIgnoreIfNullConvention(new NeverIgnoreIfNullConvention()) + .SetMemberFinderConvention(new PublicMemberFinderConvention()) + .SetSerializationOptionsConvention(new NullSerializationOptionsConvention()); + } + + // public methods + /// + /// Merges another convention profile into this one (only missing conventions are merged). + /// + /// The other convention profile. + public void Merge(ConventionProfile other) + { + if (DefaultValueConvention == null) + { + DefaultValueConvention = other.DefaultValueConvention; + } + if (ElementNameConvention == null) + { + ElementNameConvention = other.ElementNameConvention; + } + if (ExtraElementsMemberConvention == null) + { + ExtraElementsMemberConvention = other.ExtraElementsMemberConvention; + } + if (IdGeneratorConvention == null) + { + IdGeneratorConvention = other.IdGeneratorConvention; + } + if (IdMemberConvention == null) + { + IdMemberConvention = other.IdMemberConvention; + } + if (IgnoreExtraElementsConvention == null) + { + IgnoreExtraElementsConvention = other.IgnoreExtraElementsConvention; + } +#pragma warning disable 618 // SerializeDefaultValueConvention is obsolete + if (IgnoreIfDefaultConvention == null && SerializeDefaultValueConvention == null) + { + if (other.SerializeDefaultValueConvention != null) + { + SerializeDefaultValueConvention = other.SerializeDefaultValueConvention; + } + else + { + IgnoreIfDefaultConvention = other.IgnoreIfDefaultConvention; + } + } +#pragma warning restore 618 + if (IgnoreIfNullConvention == null) + { + IgnoreIfNullConvention = other.IgnoreIfNullConvention; + } + if (MemberFinderConvention == null) + { + MemberFinderConvention = other.MemberFinderConvention; + } + if (SerializationOptionsConvention == null) + { + SerializationOptionsConvention = other.SerializationOptionsConvention; + } + } + + /// + /// Sets the default value convention. + /// + /// A default value convention. + /// The convention profile. + public ConventionProfile SetDefaultValueConvention(IDefaultValueConvention convention) + { + DefaultValueConvention = convention; + return this; + } + + /// + /// Sets the element name convention. + /// + /// An element name convention. + /// The convention profile. + public ConventionProfile SetElementNameConvention(IElementNameConvention convention) + { + ElementNameConvention = convention; + return this; + } + + /// + /// Sets the extra elements member convention. + /// + /// An extra elements member convention. + /// The convention profile. + public ConventionProfile SetExtraElementsMemberConvention(IExtraElementsMemberConvention convention) + { + ExtraElementsMemberConvention = convention; + return this; + } + + /// + /// Sets the Id generator convention. + /// + /// An Id generator convention. + /// The convention profile. + public ConventionProfile SetIdGeneratorConvention(IIdGeneratorConvention convention) + { + IdGeneratorConvention = convention; + return this; + } + + /// + /// Sets the Id member convention. + /// + /// An Id member convention. + /// The convention profile. + public ConventionProfile SetIdMemberConvention(IIdMemberConvention convention) + { + IdMemberConvention = convention; + return this; + } + + /// + /// Sets the ignore extra elements convention. + /// + /// An ignore extra elements convention. + /// The convention profile. + public ConventionProfile SetIgnoreExtraElementsConvention(IIgnoreExtraElementsConvention convention) + { + IgnoreExtraElementsConvention = convention; + return this; + } + + /// + /// Sets the ignore if default convention. + /// + /// An ignore if default convention. + /// The convention profile. + public ConventionProfile SetIgnoreIfDefaultConvention(IIgnoreIfDefaultConvention convention) + { +#pragma warning disable 618 // SerializeDefaultValueConvention is obsolete + if (convention != null && SerializeDefaultValueConvention != null) + { + throw new InvalidOperationException("IgnoreIfDefaultConvention cannot be set because SerializeDefaultValueConvention is set."); + } +#pragma warning restore 618 + IgnoreIfDefaultConvention = convention; + return this; + } + + /// + /// Sets the ignore if null convention. + /// + /// An ignore if null convention. + /// The convention profile. + public ConventionProfile SetIgnoreIfNullConvention(IIgnoreIfNullConvention convention) + { + IgnoreIfNullConvention = convention; + return this; + } + + /// + /// Sets the member finder convention. + /// + /// A member finder convention. + /// The convention profile. + public ConventionProfile SetMemberFinderConvention(IMemberFinderConvention convention) + { + MemberFinderConvention = convention; + return this; + } + + /// + /// Sets the serialization options convention. + /// + /// A serialization options convention. + /// The convention profile. + public ConventionProfile SetSerializationOptionsConvention(ISerializationOptionsConvention convention) + { + SerializationOptionsConvention = convention; + return this; + } + + /// + /// Sets the serialize default value convention. + /// + /// A serialize default value convention. + /// The convention profile. + [Obsolete("SetSerializeDefaultValueConvention is obsolete and will be removed in a future version of the C# driver. Please use SetIgnoreIfDefaultConvention instead.")] + public ConventionProfile SetSerializeDefaultValueConvention(ISerializeDefaultValueConvention convention) + { + if (convention != null && IgnoreIfDefaultConvention != null) + { + throw new InvalidOperationException("SerializeDefaultValueConvention cannot be set because IgnoreIfDefaultConvention is set."); + } +#pragma warning disable 618 // SerializeDefaultValueConvention is obsolete + SerializeDefaultValueConvention = convention; +#pragma warning restore 618 + return this; + } + } +} diff --git a/Bson/Serialization/Conventions/SerializationOptionsConventions.cs b/Bson/Serialization/Conventions/SerializationOptionsConventions.cs index 4c833ee901f..ef6a028d3a0 100644 --- a/Bson/Serialization/Conventions/SerializationOptionsConventions.cs +++ b/Bson/Serialization/Conventions/SerializationOptionsConventions.cs @@ -1,101 +1,101 @@ -/* Copyright 2010-2012 10gen 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 System.Reflection; -using System.Text; - -using MongoDB.Bson.Serialization.Options; - -namespace MongoDB.Bson.Serialization.Conventions -{ - /// - /// Represents a BSON serialization options convention. - /// - public interface ISerializationOptionsConvention - { - /// - /// Gets the BSON serialization options for a member. - /// - /// The member. - /// The BSON serialization options for the member; or null to use defaults. - IBsonSerializationOptions GetSerializationOptions(MemberInfo memberInfo); - } - - /// - /// Represents BSON serialiation options that use default values. - /// - public class NullSerializationOptionsConvention : ISerializationOptionsConvention - { - /// - /// Gets the BSON serialization options for a member. - /// - /// The member. - /// - /// The BSON serialization options for the member; or null to use defaults. - /// - public IBsonSerializationOptions GetSerializationOptions(MemberInfo memberInfo) - { - return null; - } - } - - /// - /// Sets serialization options for a member of a given type. - /// - public class TypeRepresentationSerializationOptionsConvention : ISerializationOptionsConvention - { - private readonly Type _type; - private readonly BsonType _representation; - - /// - /// Initializes a new instance of the class. - /// - /// The type of the member. - /// The BSON representation to use for this type. - public TypeRepresentationSerializationOptionsConvention(Type type, BsonType representation) - { - _type = type; - _representation = representation; - } - - /// - /// Gets the BSON serialization options for a member. - /// - /// The member. - /// - /// The BSON serialization options for the member; or null to use defaults. - /// - public IBsonSerializationOptions GetSerializationOptions(MemberInfo memberInfo) - { - var propertyInfo = memberInfo as PropertyInfo; - if (propertyInfo != null && propertyInfo.PropertyType == _type) - { - return new RepresentationSerializationOptions(_representation); - } - - var fieldInfo = memberInfo as FieldInfo; - if (fieldInfo != null && fieldInfo.FieldType == _type) - { - return new RepresentationSerializationOptions(_representation); - } - - return null; - } - } - -} +/* Copyright 2010-2012 10gen 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 System.Reflection; +using System.Text; + +using MongoDB.Bson.Serialization.Options; + +namespace MongoDB.Bson.Serialization.Conventions +{ + /// + /// Represents a BSON serialization options convention. + /// + public interface ISerializationOptionsConvention + { + /// + /// Gets the BSON serialization options for a member. + /// + /// The member. + /// The BSON serialization options for the member; or null to use defaults. + IBsonSerializationOptions GetSerializationOptions(MemberInfo memberInfo); + } + + /// + /// Represents BSON serialiation options that use default values. + /// + public class NullSerializationOptionsConvention : ISerializationOptionsConvention + { + /// + /// Gets the BSON serialization options for a member. + /// + /// The member. + /// + /// The BSON serialization options for the member; or null to use defaults. + /// + public IBsonSerializationOptions GetSerializationOptions(MemberInfo memberInfo) + { + return null; + } + } + + /// + /// Sets serialization options for a member of a given type. + /// + public class TypeRepresentationSerializationOptionsConvention : ISerializationOptionsConvention + { + private readonly Type _type; + private readonly BsonType _representation; + + /// + /// Initializes a new instance of the class. + /// + /// The type of the member. + /// The BSON representation to use for this type. + public TypeRepresentationSerializationOptionsConvention(Type type, BsonType representation) + { + _type = type; + _representation = representation; + } + + /// + /// Gets the BSON serialization options for a member. + /// + /// The member. + /// + /// The BSON serialization options for the member; or null to use defaults. + /// + public IBsonSerializationOptions GetSerializationOptions(MemberInfo memberInfo) + { + var propertyInfo = memberInfo as PropertyInfo; + if (propertyInfo != null && propertyInfo.PropertyType == _type) + { + return new RepresentationSerializationOptions(_representation); + } + + var fieldInfo = memberInfo as FieldInfo; + if (fieldInfo != null && fieldInfo.FieldType == _type) + { + return new RepresentationSerializationOptions(_representation); + } + + return null; + } + } + +} diff --git a/BsonUnitTests/DefaultSerializer/BsonClassMapAutoMappingTests.cs b/BsonUnitTests/DefaultSerializer/BsonClassMapAutoMappingTests.cs index bdc791f504e..b0354c232ad 100644 --- a/BsonUnitTests/DefaultSerializer/BsonClassMapAutoMappingTests.cs +++ b/BsonUnitTests/DefaultSerializer/BsonClassMapAutoMappingTests.cs @@ -1,89 +1,89 @@ -/* Copyright 2010-2012 10gen 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 System.Text; -using NUnit.Framework; - -using MongoDB.Bson; -using MongoDB.Bson.Serialization; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Bson.Serialization.Conventions; -using MongoDB.Bson.Serialization.Options; - -namespace MongoDB.BsonUnitTests.DefaultSerializer -{ - [TestFixture] - public class BsonClassMapAutoMappingTests - { - private class A - { - public ObjectId Match { get; set; } - public string NoMatch { get; set; } - } - - private class B - { - [BsonRepresentation(BsonType.ObjectId)] - public ObjectId Match { get; set; } - } - - [Test] - public void TestMappingUsesBsonSerializationOptionsConvention() - { - var profile = new ConventionProfile() - .SetSerializationOptionsConvention(new TypeRepresentationSerializationOptionsConvention(typeof(ObjectId), BsonType.JavaScriptWithScope)); - - BsonClassMap.RegisterConventions(profile, t => t == typeof(A)); - - var classMap = BsonClassMap.LookupClassMap(typeof(A)); - - var options = classMap.GetMemberMap("Match").SerializationOptions; - Assert.IsInstanceOf(options); - Assert.AreEqual(BsonType.JavaScriptWithScope, ((RepresentationSerializationOptions)options).Representation); - } - - [Test] - public void TestMappingUsesBsonSerializationOptionsConventionDoesNotMatchWrongProperty() - { - var profile = new ConventionProfile() - .SetSerializationOptionsConvention(new TypeRepresentationSerializationOptionsConvention(typeof(ObjectId), BsonType.JavaScriptWithScope)); - - BsonClassMap.RegisterConventions(profile, t => t == typeof(A)); - - var classMap = BsonClassMap.LookupClassMap(typeof(A)); - - var options = classMap.GetMemberMap("NoMatch").SerializationOptions; - Assert.IsNull(options); - } - - [Test] - public void TestMappingWithAMatchingSerializationOptionsConventionDoesNotOverrideAttribute() - { - var profile = new ConventionProfile() - .SetSerializationOptionsConvention(new TypeRepresentationSerializationOptionsConvention(typeof(ObjectId), BsonType.JavaScriptWithScope)); - - BsonClassMap.RegisterConventions(profile, t => t == typeof(B)); - - var classMap = BsonClassMap.LookupClassMap(typeof(B)); - - var options = classMap.GetMemberMap("Match").SerializationOptions; - Assert.IsInstanceOf(options); - Assert.AreEqual(BsonType.ObjectId, ((RepresentationSerializationOptions)options).Representation); - } - } -} +/* Copyright 2010-2012 10gen 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 System.Text; +using NUnit.Framework; + +using MongoDB.Bson; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Bson.Serialization.Conventions; +using MongoDB.Bson.Serialization.Options; + +namespace MongoDB.BsonUnitTests.DefaultSerializer +{ + [TestFixture] + public class BsonClassMapAutoMappingTests + { + private class A + { + public ObjectId Match { get; set; } + public string NoMatch { get; set; } + } + + private class B + { + [BsonRepresentation(BsonType.ObjectId)] + public ObjectId Match { get; set; } + } + + [Test] + public void TestMappingUsesBsonSerializationOptionsConvention() + { + var profile = new ConventionProfile() + .SetSerializationOptionsConvention(new TypeRepresentationSerializationOptionsConvention(typeof(ObjectId), BsonType.JavaScriptWithScope)); + + BsonClassMap.RegisterConventions(profile, t => t == typeof(A)); + + var classMap = BsonClassMap.LookupClassMap(typeof(A)); + + var options = classMap.GetMemberMap("Match").SerializationOptions; + Assert.IsInstanceOf(options); + Assert.AreEqual(BsonType.JavaScriptWithScope, ((RepresentationSerializationOptions)options).Representation); + } + + [Test] + public void TestMappingUsesBsonSerializationOptionsConventionDoesNotMatchWrongProperty() + { + var profile = new ConventionProfile() + .SetSerializationOptionsConvention(new TypeRepresentationSerializationOptionsConvention(typeof(ObjectId), BsonType.JavaScriptWithScope)); + + BsonClassMap.RegisterConventions(profile, t => t == typeof(A)); + + var classMap = BsonClassMap.LookupClassMap(typeof(A)); + + var options = classMap.GetMemberMap("NoMatch").SerializationOptions; + Assert.IsNull(options); + } + + [Test] + public void TestMappingWithAMatchingSerializationOptionsConventionDoesNotOverrideAttribute() + { + var profile = new ConventionProfile() + .SetSerializationOptionsConvention(new TypeRepresentationSerializationOptionsConvention(typeof(ObjectId), BsonType.JavaScriptWithScope)); + + BsonClassMap.RegisterConventions(profile, t => t == typeof(B)); + + var classMap = BsonClassMap.LookupClassMap(typeof(B)); + + var options = classMap.GetMemberMap("Match").SerializationOptions; + Assert.IsInstanceOf(options); + Assert.AreEqual(BsonType.ObjectId, ((RepresentationSerializationOptions)options).Representation); + } + } +} diff --git a/Driver/Linq/Translators/PredicateTranslator.cs b/Driver/Linq/Translators/PredicateTranslator.cs index e828ff3ffea..3a7d2345247 100644 --- a/Driver/Linq/Translators/PredicateTranslator.cs +++ b/Driver/Linq/Translators/PredicateTranslator.cs @@ -256,6 +256,12 @@ private IMongoQuery BuildComparisonQuery(BinaryExpression binaryExpression) return query; } + query = BuildStringCaseComparisonQuery(variableExpression, operatorType, constantExpression); + if (query != null) + { + return query; + } + query = BuildTypeComparisonQuery(variableExpression, operatorType, constantExpression); if (query != null) { @@ -952,6 +958,59 @@ private IMongoQuery BuildStringLengthQuery(Expression variableExpression, Expres return null; } + private IMongoQuery BuildStringCaseComparisonQuery(Expression variableExpression, ExpressionType operatorType, ConstantExpression constantExpression) + { + var methodExpression = variableExpression as MethodCallExpression; + if (methodExpression != null) + { + var sourceExpression = methodExpression.Object as MemberExpression; + + if (methodExpression.Type == typeof(string) && sourceExpression != null) + { + var serializationInfo = _serializationInfoHelper.GetSerializationInfo(methodExpression.Object); + var serializedValue = _serializationInfoHelper.SerializeValue(serializationInfo, constantExpression.Value); + var coalescedStringValue = constantExpression.Value == null ? string.Empty : serializedValue.AsString; + + string regexPattern = "/^" + Regex.Escape(coalescedStringValue) + "$/i"; + var regex = new BsonRegularExpression(regexPattern); + + bool caseMismatch = false; + + if (methodExpression.Method.Name == "ToLower" && (coalescedStringValue != coalescedStringValue.ToLower())) + caseMismatch = true; + else if (methodExpression.Method.Name == "ToUpper" && (coalescedStringValue != coalescedStringValue.ToUpper())) + caseMismatch = true; + else if (constantExpression.Value == null) + caseMismatch = true; + + if (operatorType == ExpressionType.Equal) + { + // if comparing Foo.ToLower() == "Some Non Lower Case String" + // then that is always false for all documents + if (caseMismatch) + return Query.Exists("_id", false); + + return Query.And(Query.Exists(serializationInfo.ElementName, true), + Query.Matches(serializationInfo.ElementName, regex)); + } + else if (operatorType == ExpressionType.NotEqual) + { + // if comparing Foo.ToLower() != "Some Non Lower Case String" + // then that is always true as long as Foo is set/exists + if (caseMismatch) + return Query.Exists(serializationInfo.ElementName, true); + + return Query.And(Query.Exists(serializationInfo.ElementName, true), + Query.Not(serializationInfo.ElementName).Matches(regex)); + } + else + return null; + } + } + + return null; + } + private IMongoQuery BuildStringQuery(MethodCallExpression methodCallExpression) { if (methodCallExpression.Method.DeclaringType != typeof(string)) diff --git a/DriverUnitTests/Linq/SelectQueryTests.cs b/DriverUnitTests/Linq/SelectQueryTests.cs index edecc5324da..8cd84a4b82f 100644 --- a/DriverUnitTests/Linq/SelectQueryTests.cs +++ b/DriverUnitTests/Linq/SelectQueryTests.cs @@ -5565,6 +5565,290 @@ where c.S.TrimStart(' ', '.', '-', '\t').TrimEnd().ToLower().Contains("xyz") Assert.AreEqual(1, Consume(query)); } + [Test] + public void TestWhereSToLowerEqualsConstantLowerCaseValue() + { + var query = from c in _collection.AsQueryable() + where c.S.ToLower() == "abc" + select c; + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(C), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + Assert.AreEqual("(C c) => (c.S.ToLower() == \"abc\")", ExpressionFormatter.ToString(selectQuery.Where)); + + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"$and\" : [{ \"s\" : { \"$exists\" : true } }, { \"s\" : /^abc$/i }] }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(1, Consume(query)); + } + + [Test] + public void TestWhereSToLowerDoesNotEqualConstantLowerCaseValue() + { + var query = from c in _collection.AsQueryable() + where c.S.ToLower() != "abc" + select c; + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(C), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + Assert.AreEqual("(C c) => (c.S.ToLower() != \"abc\")", ExpressionFormatter.ToString(selectQuery.Where)); + + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"s\" : { \"$exists\" : true, \"$not\" : /^abc$/i } }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(1, Consume(query)); + } + + [Test] + public void TestWhereSToLowerEqualsConstantMixedCaseValue() + { + var query = from c in _collection.AsQueryable() + where c.S.ToLower() == "Abc" + select c; + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(C), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + Assert.AreEqual("(C c) => (c.S.ToLower() == \"Abc\")", ExpressionFormatter.ToString(selectQuery.Where)); + + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"_id\" : { \"$exists\" : false } }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(0, Consume(query)); + } + + [Test] + public void TestWhereSToLowerDoesNotEqualConstantMixedCaseValue() + { + var query = from c in _collection.AsQueryable() + where c.S.ToLower() != "Abc" + select c; + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(C), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + Assert.AreEqual("(C c) => (c.S.ToLower() != \"Abc\")", ExpressionFormatter.ToString(selectQuery.Where)); + + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"s\" : { \"$exists\" : true } }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(2, Consume(query)); + } + + [Test] + public void TestWhereSToLowerEqualsNullValue() + { + var query = from c in _collection.AsQueryable() + where c.S.ToLower() == (string)null + select c; + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(C), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"_id\" : { \"$exists\" : false } }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(0, Consume(query)); + } + + [Test] + public void TestWhereSToLowerDoesNotEqualNullValue() + { + var query = from c in _collection.AsQueryable() + where c.S.ToLower() != (string)null + select c; + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(C), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"s\" : { \"$exists\" : true } }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(2, Consume(query)); + } + + [Test] + public void TestWhereSToUpperEqualsConstantLowerCaseValue() + { + var query = from c in _collection.AsQueryable() + where c.S.ToUpper() == "abc" + select c; + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(C), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + Assert.AreEqual("(C c) => (c.S.ToUpper() == \"abc\")", ExpressionFormatter.ToString(selectQuery.Where)); + + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"_id\" : { \"$exists\" : false } }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(0, Consume(query)); + } + + [Test] + public void TestWhereSToUpperDoesNotEqualConstantLowerCaseValue() + { + var query = from c in _collection.AsQueryable() + where c.S.ToUpper() != "abc" + select c; + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(C), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + Assert.AreEqual("(C c) => (c.S.ToUpper() != \"abc\")", ExpressionFormatter.ToString(selectQuery.Where)); + + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"s\" : { \"$exists\" : true } }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(2, Consume(query)); + } + + [Test] + public void TestWhereSToUpperEqualsConstantMixedCaseValue() + { + var query = from c in _collection.AsQueryable() + where c.S.ToUpper() == "Abc" + select c; + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(C), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + Assert.AreEqual("(C c) => (c.S.ToUpper() == \"Abc\")", ExpressionFormatter.ToString(selectQuery.Where)); + + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"_id\" : { \"$exists\" : false } }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(0, Consume(query)); + } + + [Test] + public void TestWhereSToUpperDoesNotEqualConstantMixedCaseValue() + { + var query = from c in _collection.AsQueryable() + where c.S.ToUpper() != "Abc" + select c; + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(C), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + Assert.AreEqual("(C c) => (c.S.ToUpper() != \"Abc\")", ExpressionFormatter.ToString(selectQuery.Where)); + + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"s\" : { \"$exists\" : true } }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(2, Consume(query)); + } + + [Test] + public void TestWhereSToUpperEqualsNullValue() + { + var query = from c in _collection.AsQueryable() + where c.S.ToUpper() == (string)null + select c; + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(C), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"_id\" : { \"$exists\" : false } }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(0, Consume(query)); + } + + [Test] + public void TestWhereSToUpperDoesNotEqualNullValue() + { + var query = from c in _collection.AsQueryable() + where c.S.ToUpper() != (string)null + select c; + + var translatedQuery = MongoQueryTranslator.Translate(query); + Assert.IsInstanceOf(translatedQuery); + Assert.AreSame(_collection, translatedQuery.Collection); + Assert.AreSame(typeof(C), translatedQuery.DocumentType); + + var selectQuery = (SelectQuery)translatedQuery; + + Assert.IsNull(selectQuery.OrderBy); + Assert.IsNull(selectQuery.Projection); + Assert.IsNull(selectQuery.Skip); + Assert.IsNull(selectQuery.Take); + + Assert.AreEqual("{ \"s\" : { \"$exists\" : true } }", selectQuery.BuildQuery().ToJson()); + Assert.AreEqual(2, Consume(query)); + } + [Test] public void TestWhereSystemProfileInfoDurationGreatherThan10Seconds() {