Skip to content

Commit 81a4762

Browse files
author
rstam
committed
Fixed CSHARP-486. UpdateBuilder "wrapped" methods now accept C# null values. BsonDocumentWrapper now allows wrapping C# null. Since BsonDocumentWrapper.Create no longer lets null just "flow through" and wraps the null instead several places in the driver that were depending on the previous behavior of BsonDocumentWrapper.Create had to be changed.
1 parent d6cf4f5 commit 81a4762

File tree

7 files changed

+381
-71
lines changed

7 files changed

+381
-71
lines changed

Bson/ObjectModel/BsonDocumentWrapper.cs

Lines changed: 26 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
namespace MongoDB.Bson
2929
{
30-
// this class is a wrapper for an object that we intend to serialize as a BSON document
30+
// this class is a wrapper for an object that we intend to serialize as a BsonValue
3131
// it is a subclass of BsonValue so that it may be used where a BsonValue is expected
3232
// this class is mostly used by MongoCollection and MongoCursor when supporting generic query objects
3333

@@ -54,22 +54,18 @@ private BsonDocumentWrapper()
5454
/// </summary>
5555
/// <param name="wrappedObject">The wrapped object.</param>
5656
public BsonDocumentWrapper(object wrappedObject)
57-
: base(BsonType.Document)
57+
: this((wrappedObject == null) ? typeof(object) : wrappedObject.GetType(), wrappedObject)
5858
{
59-
_wrappedNominalType = (wrappedObject == null) ? typeof(object) : wrappedObject.GetType();
60-
_wrappedObject = wrappedObject;
6159
}
6260

6361
/// <summary>
6462
/// Initializes a new instance of the BsonDocumentWrapper class.
6563
/// </summary>
6664
/// <param name="wrappedNominalType">The nominal type of the wrapped object.</param>
6765
/// <param name="wrappedObject">The wrapped object.</param>
68-
public BsonDocumentWrapper(Type wrappedNominalType, object wrappedObject)
69-
: base(BsonType.Document)
66+
public BsonDocumentWrapper(Type wrappedNominalType, object value)
67+
: this(wrappedNominalType, value, false)
7068
{
71-
_wrappedNominalType = wrappedNominalType;
72-
_wrappedObject = wrappedObject;
7369
}
7470

7571
/// <summary>
@@ -78,9 +74,13 @@ public BsonDocumentWrapper(Type wrappedNominalType, object wrappedObject)
7874
/// <param name="wrappedNominalType">The nominal type of the wrapped object.</param>
7975
/// <param name="wrappedObject">The wrapped object.</param>
8076
/// <param name="isUpdateDocument">Whether the wrapped object is an update document that needs to be checked.</param>
81-
internal BsonDocumentWrapper(Type wrappedNominalType, object wrappedObject, bool isUpdateDocument)
77+
public BsonDocumentWrapper(Type wrappedNominalType, object wrappedObject, bool isUpdateDocument)
8278
: base(BsonType.Document)
8379
{
80+
if (wrappedNominalType == null)
81+
{
82+
throw new ArgumentNullException("wrappedNominalType");
83+
}
8484
_wrappedNominalType = wrappedNominalType;
8585
_wrappedObject = wrappedObject;
8686
_isUpdateDocument = isUpdateDocument;
@@ -92,7 +92,7 @@ internal BsonDocumentWrapper(Type wrappedNominalType, object wrappedObject, bool
9292
/// </summary>
9393
/// <typeparam name="TNominalType">The nominal type of the wrapped object.</typeparam>
9494
/// <param name="value">The wrapped object.</param>
95-
/// <returns>A BsonDocumentWrapper or null.</returns>
95+
/// <returns>A BsonDocumentWrapper.</returns>
9696
public static BsonDocumentWrapper Create<TNominalType>(TNominalType value)
9797
{
9898
return Create(typeof(TNominalType), value);
@@ -104,7 +104,7 @@ public static BsonDocumentWrapper Create<TNominalType>(TNominalType value)
104104
/// <typeparam name="TNominalType">The nominal type of the wrapped object.</typeparam>
105105
/// <param name="value">The wrapped object.</param>
106106
/// <param name="isUpdateDocument">Whether the wrapped object is an update document.</param>
107-
/// <returns>A BsonDocumentWrapper or null.</returns>
107+
/// <returns>A BsonDocumentWrapper.</returns>
108108
public static BsonDocumentWrapper Create<TNominalType>(TNominalType value, bool isUpdateDocument)
109109
{
110110
return Create(typeof(TNominalType), value, isUpdateDocument);
@@ -115,7 +115,7 @@ public static BsonDocumentWrapper Create<TNominalType>(TNominalType value, bool
115115
/// </summary>
116116
/// <param name="nominalType">The nominal type of the wrapped object.</param>
117117
/// <param name="value">The wrapped object.</param>
118-
/// <returns>A BsonDocumentWrapper or null.</returns>
118+
/// <returns>A BsonDocumentWrapper.</returns>
119119
public static BsonDocumentWrapper Create(Type nominalType, object value)
120120
{
121121
return Create(nominalType, value, false); // isUpdateDocument = false
@@ -127,61 +127,46 @@ public static BsonDocumentWrapper Create(Type nominalType, object value)
127127
/// <param name="nominalType">The nominal type of the wrapped object.</param>
128128
/// <param name="value">The wrapped object.</param>
129129
/// <param name="isUpdateDocument">Whether the wrapped object is an update document.</param>
130-
/// <returns>A BsonDocumentWrapper or null.</returns>
130+
/// <returns>A BsonDocumentWrapper.</returns>
131131
public static BsonDocumentWrapper Create(Type nominalType, object value, bool isUpdateDocument)
132132
{
133-
if (value != null)
134-
{
135-
return new BsonDocumentWrapper(nominalType, value, isUpdateDocument);
136-
}
137-
else
138-
{
139-
return null;
140-
}
133+
return new BsonDocumentWrapper(nominalType, value, isUpdateDocument);
141134
}
142135

143136
/// <summary>
144137
/// Creates a list of new instances of the BsonDocumentWrapper class.
145138
/// </summary>
146139
/// <typeparam name="TNominalType">The nominal type of the wrapped objects.</typeparam>
147140
/// <param name="values">A list of wrapped objects.</param>
148-
/// <returns>A list of BsonDocumentWrappers or null.</returns>
141+
/// <returns>A list of BsonDocumentWrappers.</returns>
149142
public static IEnumerable<BsonDocumentWrapper> CreateMultiple<TNominalType>(IEnumerable<TNominalType> values)
150143
{
151-
if (values != null)
152-
{
153-
return values.Where(v => v != null).Select(v => new BsonDocumentWrapper(typeof(TNominalType), v));
154-
}
155-
else
144+
if (values == null)
156145
{
157-
return null;
146+
throw new ArgumentNullException("values");
158147
}
148+
149+
return values.Select(v => new BsonDocumentWrapper(typeof(TNominalType), v));
159150
}
160151

161152
/// <summary>
162153
/// Creates a list of new instances of the BsonDocumentWrapper class.
163154
/// </summary>
164155
/// <param name="nominalType">The nominal type of the wrapped object.</param>
165156
/// <param name="values">A list of wrapped objects.</param>
166-
/// <returns>A list of BsonDocumentWrappers or null.</returns>
157+
/// <returns>A list of BsonDocumentWrappers.</returns>
167158
public static IEnumerable<BsonDocumentWrapper> CreateMultiple(Type nominalType, IEnumerable values)
168159
{
169-
if (values != null)
160+
if (nominalType == null)
170161
{
171-
var wrappers = new List<BsonDocumentWrapper>();
172-
foreach (var value in values)
173-
{
174-
if (value != null)
175-
{
176-
wrappers.Add(new BsonDocumentWrapper(nominalType, value));
177-
}
178-
}
179-
return wrappers;
162+
throw new ArgumentNullException("nominalType");
180163
}
181-
else
164+
if (values == null)
182165
{
183-
return null;
166+
throw new ArgumentNullException("values");
184167
}
168+
169+
return values.Cast<object>().Select(v => new BsonDocumentWrapper(nominalType, v));
185170
}
186171

187172
// public methods

BsonUnitTests/BsonUnitTests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@
160160
<Compile Include="ObjectModel\BsonArrayTests.cs" />
161161
<Compile Include="ObjectModel\BsonBinaryDataTests.cs" />
162162
<Compile Include="ObjectModel\BsonDocumentTests.cs" />
163+
<Compile Include="ObjectModel\BsonDocumentWrapperTests.cs" />
163164
<Compile Include="ObjectModel\BsonElementTests.cs" />
164165
<Compile Include="ObjectModel\BsonEqualsTests.cs" />
165166
<Compile Include="IO\JsonWriterTests.cs" />
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
/* Copyright 2010-2012 10gen Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using System;
17+
using System.Collections.Generic;
18+
using System.Linq;
19+
using System.Text;
20+
using NUnit.Framework;
21+
22+
using MongoDB.Bson;
23+
24+
namespace MongoDB.BsonUnitTests
25+
{
26+
[TestFixture]
27+
public class BsonDocumentWrapperTests
28+
{
29+
private class C
30+
{
31+
public int X { get; set; }
32+
}
33+
34+
private C _c = new C { X = 1 };
35+
36+
[Test]
37+
public void TestConstructorWithObject()
38+
{
39+
var wrapper = new BsonDocumentWrapper(_c);
40+
var expected = "{ \"X\" : 1 }";
41+
Assert.AreEqual(expected, wrapper.ToJson());
42+
}
43+
44+
[Test]
45+
public void TestConstructorWithNullObject()
46+
{
47+
var wrapper = new BsonDocumentWrapper(null);
48+
var expected = "null";
49+
Assert.AreEqual(expected, wrapper.ToJson());
50+
}
51+
52+
[Test]
53+
public void TestConstructorWithNominalTypeAndObject()
54+
{
55+
var wrapper = new BsonDocumentWrapper(typeof(C), _c);
56+
var expected = "{ \"X\" : 1 }";
57+
Assert.AreEqual(expected, wrapper.ToJson());
58+
}
59+
60+
[Test]
61+
public void TestConstructorWithNominalTypeAndNullObject()
62+
{
63+
var wrapper = new BsonDocumentWrapper(typeof(C), null);
64+
var expected = "null";
65+
Assert.AreEqual(expected, wrapper.ToJson());
66+
}
67+
68+
[Test]
69+
public void TestConstructorWithNullNominalTypeAndObject()
70+
{
71+
Assert.Throws<ArgumentNullException>(() => { var wrapper = new BsonDocumentWrapper(null, _c); });
72+
}
73+
74+
[Test]
75+
public void TestConstructorWithNominalTypeAndObjectAndIsUpdateDocument()
76+
{
77+
var wrapper = new BsonDocumentWrapper(typeof(C), _c, false);
78+
var expected = "{ \"X\" : 1 }";
79+
Assert.AreEqual(expected, wrapper.ToJson());
80+
}
81+
82+
[Test]
83+
public void TestConstructorWithNominalTypeAndNullObjectAndIsUpdateDocument()
84+
{
85+
var wrapper = new BsonDocumentWrapper(typeof(C), null, false);
86+
var expected = "null";
87+
Assert.AreEqual(expected, wrapper.ToJson());
88+
}
89+
90+
[Test]
91+
public void TestConstructorWithNullNominalTypeAndObjectAndIsUpdateDocument()
92+
{
93+
Assert.Throws<ArgumentNullException>(() => { var wrapper = new BsonDocumentWrapper(null, _c, false); });
94+
}
95+
96+
[Test]
97+
public void TestCreateGenericWithValue()
98+
{
99+
var wrapper = BsonDocumentWrapper.Create<C>(_c);
100+
var expected = "{ \"X\" : 1 }";
101+
Assert.AreEqual(expected, wrapper.ToJson());
102+
}
103+
104+
[Test]
105+
public void TestCreateGenericWithNullValue()
106+
{
107+
var wrapper = BsonDocumentWrapper.Create<C>(null);
108+
var expected = "null";
109+
Assert.AreEqual(expected, wrapper.ToJson());
110+
}
111+
112+
[Test]
113+
public void TestCreateGenericWithValueAndIsUpdateDocument()
114+
{
115+
var wrapper = BsonDocumentWrapper.Create<C>(_c, false);
116+
var expected = "{ \"X\" : 1 }";
117+
Assert.AreEqual(expected, wrapper.ToJson());
118+
}
119+
120+
[Test]
121+
public void TestCreateGenericWithNullValueAndIsUpdateDocument()
122+
{
123+
var wrapper = BsonDocumentWrapper.Create<C>(null, false);
124+
var expected = "null";
125+
Assert.AreEqual(expected, wrapper.ToJson());
126+
}
127+
128+
[Test]
129+
public void TestCreateWithNominalTypeAndValue()
130+
{
131+
var wrapper = BsonDocumentWrapper.Create(typeof(C), _c);
132+
var expected = "{ \"X\" : 1 }";
133+
Assert.AreEqual(expected, wrapper.ToJson());
134+
}
135+
136+
[Test]
137+
public void TestCreateWithNominalTypeAndNullValue()
138+
{
139+
var wrapper = BsonDocumentWrapper.Create(typeof(C), null);
140+
var expected = "null";
141+
Assert.AreEqual(expected, wrapper.ToJson());
142+
}
143+
144+
[Test]
145+
public void TestCreateWithNullNominalTypeAndValue()
146+
{
147+
Assert.Throws<ArgumentNullException>(() => { var wrapper = BsonDocumentWrapper.Create(null, _c); });
148+
}
149+
150+
[Test]
151+
public void TestCreateWithNominalTypeAndValueAndIsUpdateDocument()
152+
{
153+
var wrapper = BsonDocumentWrapper.Create(typeof(C), _c, false);
154+
var expected = "{ \"X\" : 1 }";
155+
Assert.AreEqual(expected, wrapper.ToJson());
156+
}
157+
158+
[Test]
159+
public void TestCreateWithNominalTypeAndNullValueAndIsUpdateDocument()
160+
{
161+
var wrapper = BsonDocumentWrapper.Create(typeof(C), null, false);
162+
var expected = "null";
163+
Assert.AreEqual(expected, wrapper.ToJson());
164+
}
165+
166+
[Test]
167+
public void TestCreateWithNullNominalTypeAndValueAndIsUpdateDocument()
168+
{
169+
Assert.Throws<ArgumentNullException>(() => { var wrapper = BsonDocumentWrapper.Create(null, _c, false); });
170+
}
171+
172+
[Test]
173+
public void TestCreateMultipleGenericWithValues()
174+
{
175+
var wrappers = BsonDocumentWrapper.CreateMultiple<C>(new C[] { _c, null });
176+
var expected = "[{ \"X\" : 1 }, null]";
177+
Assert.AreEqual(expected, wrappers.ToJson());
178+
}
179+
180+
[Test]
181+
public void TestCreateMultipleGenericWithNullValues()
182+
{
183+
Assert.Throws<ArgumentNullException>(() => { var wrappers = BsonDocumentWrapper.CreateMultiple<C>(null); });
184+
}
185+
186+
[Test]
187+
public void TestCreateMultipleWithNominalTypeAndValues()
188+
{
189+
var wrappers = BsonDocumentWrapper.CreateMultiple(typeof(C), new C[] { _c, null });
190+
var expected = "[{ \"X\" : 1 }, null]";
191+
Assert.AreEqual(expected, wrappers.ToJson());
192+
}
193+
194+
[Test]
195+
public void TestCreateMultipleWithNullNominalTypeAndValues()
196+
{
197+
Assert.Throws<ArgumentNullException>(() => { var wrappers = BsonDocumentWrapper.CreateMultiple(null, new C[] { _c, null }); });
198+
}
199+
200+
[Test]
201+
public void TestCreateMultipleWithNominalTypeAndNullValues()
202+
{
203+
Assert.Throws<ArgumentNullException>(() => { var wrappers = BsonDocumentWrapper.CreateMultiple(typeof(C), null); });
204+
}
205+
}
206+
}

Driver/Builders/UpdateBuilder.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,6 @@ public UpdateBuilder AddToSetEachWrapped<T>(string name, params T[] values)
612612
public UpdateBuilder AddToSetWrapped<T>(string name, T value)
613613
{
614614
if (name == null) { throw new ArgumentNullException("name"); }
615-
if (value == null) { throw new ArgumentNullException("value"); }
616615
var wrappedValue = (BsonValue)BsonDocumentWrapper.Create(value); // the cast to BsonValue is required
617616
return AddToSet(name, wrappedValue);
618617
}
@@ -914,7 +913,6 @@ public UpdateBuilder PullAllWrapped<T>(string name, params T[] values)
914913
public UpdateBuilder PullWrapped<T>(string name, T value)
915914
{
916915
if (name == null) { throw new ArgumentNullException("name"); }
917-
if (value == null) { throw new ArgumentNullException("value"); }
918916
var wrappedValue = BsonDocumentWrapper.Create(value);
919917
BsonElement element;
920918
if (_document.TryGetElement("$pull", out element))
@@ -1046,7 +1044,6 @@ public UpdateBuilder PushAllWrapped<T>(string name, params T[] values)
10461044
public UpdateBuilder PushWrapped<T>(string name, T value)
10471045
{
10481046
if (name == null) { throw new ArgumentNullException("name"); }
1049-
if (value == null) { throw new ArgumentNullException("value"); }
10501047
var wrappedValue = BsonDocumentWrapper.Create<T>(value);
10511048
BsonElement element;
10521049
if (_document.TryGetElement("$push", out element))
@@ -1114,7 +1111,6 @@ public UpdateBuilder Set(string name, BsonValue value)
11141111
public UpdateBuilder SetWrapped<T>(string name, T value)
11151112
{
11161113
if (name == null) { throw new ArgumentNullException("name"); }
1117-
if (value == null) { throw new ArgumentNullException("value"); }
11181114
var wrappedValue = BsonDocumentWrapper.Create<T>(value);
11191115
BsonElement element;
11201116
if (_document.TryGetElement("$set", out element))

0 commit comments

Comments
 (0)