Browse Source
CSHARP-2239: Refactor ChangeStreamDocument to be a BsonDocumentBackedClass.
pull/327/head
CSHARP-2239: Refactor ChangeStreamDocument to be a BsonDocumentBackedClass.
pull/327/head

16 changed files with 572 additions and 312 deletions
-
34src/MongoDB.Bson/Serialization/Serializers/BsonDocumentBackedClassSerializer.cs
-
64src/MongoDB.Driver.Core/ChangeStreamDocument.cs
-
76src/MongoDB.Driver.Core/ChangeStreamDocumentCollectionNamespaceSerializer.cs
-
158src/MongoDB.Driver.Core/ChangeStreamDocumentSerializer.cs
-
14src/MongoDB.Driver.Core/ChangeStreamOperationTypeSerializer.cs
-
26src/MongoDB.Driver.Core/ChangeStreamUpdateDescription.cs
-
11src/MongoDB.Driver.Core/ChangeStreamUpdateDescriptionSerializer.cs
-
1src/MongoDB.Driver.Core/MongoDB.Driver.Core.csproj
-
12tests/MongoDB.Bson.TestHelpers/Reflector.cs
-
2tests/MongoDB.Bson.Tests/MongoDB.Bson.Tests.csproj
-
30tests/MongoDB.Bson.Tests/Serialization/BsonDocumentBackedClassTests.cs
-
32tests/MongoDB.Bson.Tests/Serialization/Serializers/BsonDocumentBackedClassSerializerTests.cs
-
1tests/MongoDB.Driver.Core.Tests.Dotnet/MongoDB.Driver.Core.Tests.Dotnet.csproj
-
156tests/MongoDB.Driver.Core.Tests/ChangeStreamDocumentSerializerTests.cs
-
262tests/MongoDB.Driver.Core.Tests/ChangeStreamDocumentTests.cs
-
5tests/MongoDB.Driver.Core.Tests/MongoDB.Driver.Core.Tests.csproj
@ -0,0 +1,76 @@ |
|||
/* Copyright 2018-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 MongoDB.Bson.IO; |
|||
using MongoDB.Bson.Serialization; |
|||
using MongoDB.Bson.Serialization.Serializers; |
|||
|
|||
namespace MongoDB.Driver |
|||
{ |
|||
internal class ChangeStreamDocumentCollectionNamespaceSerializer : SealedClassSerializerBase<CollectionNamespace> |
|||
{ |
|||
#region static
|
|||
// private static fields
|
|||
private static readonly ChangeStreamDocumentCollectionNamespaceSerializer __instance = new ChangeStreamDocumentCollectionNamespaceSerializer(); |
|||
|
|||
// public static properties
|
|||
public static ChangeStreamDocumentCollectionNamespaceSerializer Instance => __instance; |
|||
#endregion
|
|||
|
|||
// public methods
|
|||
public override CollectionNamespace Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) |
|||
{ |
|||
var reader = context.Reader; |
|||
string collectionName = null; |
|||
string databaseName = null; |
|||
|
|||
reader.ReadStartDocument(); |
|||
while (reader.ReadBsonType() != 0) |
|||
{ |
|||
var fieldName = reader.ReadName(); |
|||
switch (fieldName) |
|||
{ |
|||
case "db": |
|||
databaseName = reader.ReadString(); |
|||
break; |
|||
|
|||
case "coll": |
|||
collectionName = reader.ReadString(); |
|||
break; |
|||
|
|||
default: |
|||
throw new FormatException($"Invalid field name: \"{fieldName}\"."); |
|||
} |
|||
} |
|||
reader.ReadEndDocument(); |
|||
|
|||
var databaseNamespace = new DatabaseNamespace(databaseName); |
|||
return new CollectionNamespace(databaseNamespace, collectionName); |
|||
} |
|||
|
|||
protected override void SerializeValue(BsonSerializationContext context, BsonSerializationArgs args, CollectionNamespace value) |
|||
{ |
|||
var writer = context.Writer; |
|||
|
|||
writer.WriteStartDocument(); |
|||
writer.WriteName("db"); |
|||
writer.WriteString(value.DatabaseNamespace.DatabaseName); |
|||
writer.WriteName("coll"); |
|||
writer.WriteString(value.CollectionName); |
|||
writer.WriteEndDocument(); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,30 @@ |
|||
/* Copyright 2018-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.Reflection; |
|||
using MongoDB.Bson.Serialization; |
|||
using MongoDB.Bson.TestHelpers; |
|||
|
|||
namespace MongoDB.Bson.Tests.Serialization |
|||
{ |
|||
public class BsonDocumentBackedClassTests |
|||
{ |
|||
} |
|||
|
|||
public static class BsonDocumentBackedClassReflector |
|||
{ |
|||
public static IBsonDocumentSerializer _serializer(this BsonDocumentBackedClass obj) => (IBsonDocumentSerializer)Reflector.GetFieldValue(obj, nameof(_serializer), BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy); |
|||
} |
|||
} |
@ -0,0 +1,32 @@ |
|||
/* Copyright 2018-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.Collections.Generic; |
|||
using MongoDB.Bson.Serialization; |
|||
using MongoDB.Bson.TestHelpers; |
|||
|
|||
namespace MongoDB.Bson.Tests.Serialization.Serializers |
|||
{ |
|||
public class BsonDocumentBackedClassSerializerTests |
|||
{ |
|||
} |
|||
|
|||
public static class BsonDocumentBackedClassSerializerReflector |
|||
{ |
|||
public static Dictionary<string, BsonSerializationInfo> _memberSerializationInfo<TClass>(this BsonDocumentBackedClassSerializer<TClass> obj) |
|||
where TClass : BsonDocumentBackedClass |
|||
=> (Dictionary<string, BsonSerializationInfo>)Reflector.GetFieldValue(obj, nameof(_memberSerializationInfo)); |
|||
} |
|||
} |
@ -0,0 +1,262 @@ |
|||
/* Copyright 2018-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 FluentAssertions; |
|||
using MongoDB.Bson; |
|||
using MongoDB.Bson.Serialization; |
|||
using MongoDB.Bson.Serialization.Serializers; |
|||
using MongoDB.Bson.Tests.Serialization; |
|||
using Moq; |
|||
using Xunit; |
|||
|
|||
namespace MongoDB.Driver |
|||
{ |
|||
public class ChangeStreamDocumentTests |
|||
{ |
|||
[Fact] |
|||
public void constructor_should_initialize_instance() |
|||
{ |
|||
var backingDocument = new BsonDocument(); |
|||
var documentSerializer = Mock.Of<IBsonSerializer<BsonDocument>>(); |
|||
|
|||
var result = new ChangeStreamDocument<BsonDocument>(backingDocument, documentSerializer); |
|||
|
|||
result.BackingDocument.Should().BeSameAs(backingDocument); |
|||
var changeStreamDocumentSerializer = result._serializer().Should().BeOfType<ChangeStreamDocumentSerializer<BsonDocument>>().Subject; |
|||
changeStreamDocumentSerializer._documentSerializer().Should().BeSameAs(documentSerializer); |
|||
} |
|||
|
|||
[Fact] |
|||
public void constructor_should_throw_when_backingDocument_is_null() |
|||
{ |
|||
var documentSerializer = Mock.Of<IBsonSerializer<BsonDocument>>(); |
|||
|
|||
var exception = Record.Exception(() => new ChangeStreamDocument<BsonDocument>(null, documentSerializer)); |
|||
|
|||
var e = exception.Should().BeOfType<ArgumentNullException>().Subject; |
|||
e.ParamName.Should().Be("backingDocument"); |
|||
} |
|||
|
|||
[Fact] |
|||
public void constructor_should_throw_when_documentSerializer_is_null() |
|||
{ |
|||
var backingDocument = new BsonDocument(); |
|||
|
|||
var exception = Record.Exception(() => new ChangeStreamDocument<BsonDocument>(backingDocument, null)); |
|||
|
|||
var e = exception.Should().BeOfType<ArgumentNullException>().Subject; |
|||
e.ParamName.Should().Be("documentSerializer"); |
|||
} |
|||
|
|||
[Fact] |
|||
public void BackingDocument_should_return_expected_result() |
|||
{ |
|||
var backingDocument = new BsonDocument(); |
|||
var subject = CreateSubject(backingDocument: backingDocument); |
|||
|
|||
var result = subject.BackingDocument; |
|||
|
|||
result.Should().BeSameAs(backingDocument); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ClusterTime_should_return_expected_result() |
|||
{ |
|||
var value = new BsonDocument("x", 1234); |
|||
var backingDocument = new BsonDocument { { "other", 1 }, { "clusterTime", value } }; |
|||
var subject = CreateSubject(backingDocument: backingDocument); |
|||
|
|||
var result = subject.ClusterTime; |
|||
|
|||
result.Should().Be(value); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ClusterTime_should_return_null_when_not_present() |
|||
{ |
|||
var value = new BsonDocument("x", 1234); |
|||
var backingDocument = new BsonDocument { { "other", 1 } }; |
|||
var subject = CreateSubject(backingDocument: backingDocument); |
|||
|
|||
var result = subject.ClusterTime; |
|||
|
|||
result.Should().BeNull(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void CollectionNamespace_should_return_expected_result() |
|||
{ |
|||
var value = new CollectionNamespace(new DatabaseNamespace("database"), "collection"); |
|||
var ns = new BsonDocument { { "db", value.DatabaseNamespace.DatabaseName }, { "coll", value.CollectionName } }; |
|||
var backingDocument = new BsonDocument { { "other", 1 }, { "ns", ns } }; |
|||
var subject = CreateSubject(backingDocument: backingDocument); |
|||
|
|||
var result = subject.CollectionNamespace; |
|||
|
|||
result.Should().Be(value); |
|||
} |
|||
|
|||
[Fact] |
|||
public void CollectionNamespace_should_return_null_when_not_present() |
|||
{ |
|||
var value = new BsonDocument("x", 1234); |
|||
var backingDocument = new BsonDocument { { "other", 1 } }; |
|||
var subject = CreateSubject(backingDocument: backingDocument); |
|||
|
|||
var result = subject.CollectionNamespace; |
|||
|
|||
result.Should().BeNull(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void DocumentKey_should_return_expected_result() |
|||
{ |
|||
var value = new BsonDocument("x", 1234); |
|||
var backingDocument = new BsonDocument { { "other", 1 }, { "documentKey", value } }; |
|||
var subject = CreateSubject(backingDocument: backingDocument); |
|||
|
|||
var result = subject.DocumentKey; |
|||
|
|||
result.Should().Be(value); |
|||
} |
|||
|
|||
[Fact] |
|||
public void DocumentKey_should_return_null_when_not_present() |
|||
{ |
|||
var value = new BsonDocument("x", 1234); |
|||
var backingDocument = new BsonDocument { { "other", 1 } }; |
|||
var subject = CreateSubject(backingDocument: backingDocument); |
|||
|
|||
var result = subject.DocumentKey; |
|||
|
|||
result.Should().BeNull(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void FullDocument_should_return_expected_result() |
|||
{ |
|||
var value = new BsonDocument("x", 1234); |
|||
var backingDocument = new BsonDocument { { "other", 1 }, { "fullDocument", value } }; |
|||
var subject = CreateSubject(backingDocument: backingDocument); |
|||
|
|||
var result = subject.FullDocument; |
|||
|
|||
result.Should().Be(value); |
|||
} |
|||
|
|||
[Fact] |
|||
public void FullDocument_should_return_null_when_not_present() |
|||
{ |
|||
var value = new BsonDocument("x", 1234); |
|||
var backingDocument = new BsonDocument { { "other", 1 } }; |
|||
var subject = CreateSubject(backingDocument: backingDocument); |
|||
|
|||
var result = subject.FullDocument; |
|||
|
|||
result.Should().BeNull(); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData("insert", ChangeStreamOperationType.Insert)] |
|||
[InlineData("update", ChangeStreamOperationType.Update)] |
|||
[InlineData("replace", ChangeStreamOperationType.Replace)] |
|||
[InlineData("delete", ChangeStreamOperationType.Delete)] |
|||
public void OperationType_should_return_expected_result(string operationTypeName, ChangeStreamOperationType expectedResult) |
|||
{ |
|||
var backingDocument = new BsonDocument { { "other", 1 }, { "operationType", operationTypeName } }; |
|||
var subject = CreateSubject(backingDocument: backingDocument); |
|||
|
|||
var result = subject.OperationType; |
|||
|
|||
result.Should().Be(expectedResult); |
|||
} |
|||
|
|||
[Fact] |
|||
public void OperationType_should_return_minus_one_when_not_present() |
|||
{ |
|||
var value = new BsonDocument("x", 1234); |
|||
var backingDocument = new BsonDocument { { "other", 1 } }; |
|||
var subject = CreateSubject(backingDocument: backingDocument); |
|||
|
|||
var result = subject.OperationType; |
|||
|
|||
result.Should().Be((ChangeStreamOperationType)(-1)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ResumeToken_should_return_expected_result() |
|||
{ |
|||
var value = new BsonDocument("x", 1234); |
|||
var backingDocument = new BsonDocument { { "other", 1 }, { "_id", value } }; |
|||
var subject = CreateSubject(backingDocument: backingDocument); |
|||
|
|||
var result = subject.ResumeToken; |
|||
|
|||
result.Should().Be(value); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ResumeToken_should_return_null_when_not_present() |
|||
{ |
|||
var value = new BsonDocument("x", 1234); |
|||
var backingDocument = new BsonDocument { { "other", 1 } }; |
|||
var subject = CreateSubject(backingDocument: backingDocument); |
|||
|
|||
var result = subject.ResumeToken; |
|||
|
|||
result.Should().BeNull(); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData("{}", new string[0])] |
|||
[InlineData("{ x : 1 }", new[] { "a", "b", "c" })] |
|||
public void UpdateDescription_should_return_expected_result(string updatedFieldsJson, string[] removedFields) |
|||
{ |
|||
var updatedFields = BsonDocument.Parse(updatedFieldsJson); |
|||
var updateDescriptionDocument = new BsonDocument { { "updatedFields", updatedFields }, { "removedFields", new BsonArray(removedFields) } }; |
|||
var backingDocument = new BsonDocument { { "other", 1 }, { "updateDescription", updateDescriptionDocument } }; |
|||
var subject = CreateSubject(backingDocument: backingDocument); |
|||
|
|||
var result = subject.UpdateDescription; |
|||
|
|||
var expectedResult = new ChangeStreamUpdateDescription(updatedFields, removedFields); |
|||
result.Should().Be(expectedResult); |
|||
} |
|||
|
|||
[Fact] |
|||
public void UpdateDescription_should_return_null_when_not_present() |
|||
{ |
|||
var value = new BsonDocument("x", 1234); |
|||
var backingDocument = new BsonDocument { { "other", 1 } }; |
|||
var subject = CreateSubject(backingDocument: backingDocument); |
|||
|
|||
var result = subject.UpdateDescription; |
|||
|
|||
result.Should().BeNull(); |
|||
} |
|||
|
|||
// private methods
|
|||
private ChangeStreamDocument<BsonDocument> CreateSubject( |
|||
BsonDocument backingDocument = null, |
|||
IBsonSerializer<BsonDocument> documentSerializer = null) |
|||
{ |
|||
backingDocument = backingDocument ?? new BsonDocument(); |
|||
documentSerializer = documentSerializer ?? BsonDocumentSerializer.Instance; |
|||
|
|||
return new ChangeStreamDocument<BsonDocument>(backingDocument, documentSerializer); |
|||
} |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue