Skip to content

Commit 8228c21

Browse files
committed
CSHARP-5572: Fixed some issues with KeyValuePair.
1 parent c56bd0c commit 8228c21

File tree

5 files changed

+63
-25
lines changed

5 files changed

+63
-25
lines changed

src/MongoDB.Driver/Linq/Linq3Implementation/KnownSerializerFinders/KnownSerializerFinderVisitMethodCall.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
using MongoDB.Driver.Linq.Linq3Implementation.Misc;
2929
using MongoDB.Driver.Linq.Linq3Implementation.Reflection;
3030
using MongoDB.Driver.Linq.Linq3Implementation.Serializers;
31+
using MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators;
3132

3233
namespace MongoDB.Driver.Linq.Linq3Implementation.KnownSerializerFinders;
3334

@@ -1625,10 +1626,8 @@ void DeduceCreateMethodSerializers()
16251626
var keyExpression = arguments[0];
16261627
var valueExpression = arguments[1];
16271628

1628-
if (nodeSerializer is IKeyValuePairSerializer keyValuePairSerializer)
1629+
if (nodeSerializer.IsKeyValuePairSerializer(out _, out _, out var keySerializer, out var valueSerializer))
16291630
{
1630-
var keySerializer = keyValuePairSerializer.KeySerializer;
1631-
var valueSerializer = keyValuePairSerializer.ValueSerializer;
16321631
DeduceSerializer(keyExpression, keySerializer);
16331632
DeduceSerializer(valueExpression, valueSerializer);
16341633
}
@@ -1638,7 +1637,12 @@ void DeduceCreateMethodSerializers()
16381637
{
16391638
var keySerializer = argumentSerializers[0];
16401639
var valueSerializer = argumentSerializers[1];
1641-
var keyValuePairSerializer = KeyValuePairSerializer.Create(BsonType.Document, keySerializer, valueSerializer);
1640+
var keyValuePairSerializer = NewKeyValuePairExpressionToAggregationExpressionTranslator.CreateResultSerializer(
1641+
resultType: method.ReturnType,
1642+
keySerializer,
1643+
valueSerializer,
1644+
out _,
1645+
out _);
16421646
AddKnownSerializer(node, keyValuePairSerializer);
16431647
}
16441648
}

src/MongoDB.Driver/Linq/Linq3Implementation/KnownSerializerFinders/KnownSerializerFinderVisitNew.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
using MongoDB.Driver.Linq.Linq3Implementation.Misc;
2424
using MongoDB.Driver.Linq.Linq3Implementation.Reflection;
2525
using MongoDB.Driver.Linq.Linq3Implementation.Serializers;
26+
using MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators;
2627

2728
namespace MongoDB.Driver.Linq.Linq3Implementation.KnownSerializerFinders;
2829

@@ -89,10 +90,8 @@ IBsonSerializer GetKnownSerializer(ConstructorInfo constructor)
8990
{
9091
var collectionExpression = arguments[0];
9192
if (IsItemSerializerKnown(collectionExpression, out var itemSerializer) &&
92-
itemSerializer is IKeyValuePairSerializer keyValuePairSerializer)
93+
itemSerializer.IsKeyValuePairSerializer(out _, out _, out var keySerializer, out var valueSerializer))
9394
{
94-
var keySerializer = keyValuePairSerializer.KeySerializer;
95-
var valueSerializer = keyValuePairSerializer.ValueSerializer;
9695
return DictionarySerializer.Create(keySerializer, valueSerializer);
9796
}
9897
}
@@ -119,7 +118,12 @@ IBsonSerializer GetKnownSerializer(ConstructorInfo constructor)
119118
if (IsKnown(key, out var keySerializer) &&
120119
IsKnown(value, out var valueSerializer))
121120
{
122-
return KeyValuePairSerializer.Create(BsonType.Document, keySerializer, valueSerializer);
121+
return NewKeyValuePairExpressionToAggregationExpressionTranslator.CreateResultSerializer(
122+
resultType: node.Type,
123+
keySerializer,
124+
valueSerializer,
125+
out _,
126+
out _);
123127
}
124128
}
125129
else if (TupleOrValueTupleConstructor.IsTupleOrValueTupleConstructor(constructor))

src/MongoDB.Driver/Linq/Linq3Implementation/Misc/IBsonSerializerExtensions.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@
1313
* limitations under the License.
1414
*/
1515

16+
using System.Collections.Generic;
1617
using System.Linq.Expressions;
1718
using MongoDB.Bson;
1819
using MongoDB.Bson.Serialization;
20+
using MongoDB.Bson.Serialization.Serializers;
1921
using MongoDB.Driver.Linq.Linq3Implementation.ExtensionMethods;
2022
using MongoDB.Driver.Linq.Linq3Implementation.Serializers;
2123

@@ -80,4 +82,42 @@ public static bool HasNumericRepresentation(this IBsonSerializer serializer)
8082
serializer is IHasRepresentationSerializer hasRepresentationSerializer &&
8183
hasRepresentationSerializer.Representation.IsNumeric();
8284
}
85+
86+
public static bool IsKeyValuePairSerializer(
87+
this IBsonSerializer serializer,
88+
out string keyElementName,
89+
out string valueElementName,
90+
out IBsonSerializer keySerializer,
91+
out IBsonSerializer valueSerializer)
92+
{
93+
if (serializer is IKeyValuePairSerializer keyValuePairSerializer)
94+
{
95+
keyElementName = "k";
96+
valueElementName = "v";
97+
keySerializer = keyValuePairSerializer.KeySerializer;
98+
valueSerializer = keyValuePairSerializer.ValueSerializer;
99+
return true;
100+
}
101+
102+
// for backward compatibility not all KeyValuePair serializers implement IKeyValuePairSerializer
103+
if (serializer.ValueType is var valueType &&
104+
valueType.IsConstructedGenericType &&
105+
valueType.GetGenericTypeDefinition() == typeof(KeyValuePair<,>) &&
106+
serializer is IBsonDocumentSerializer documentSerializer &&
107+
documentSerializer.TryGetMemberSerializationInfo("Key", out var keySerializationInfo) &&
108+
documentSerializer.TryGetMemberSerializationInfo("Value", out var valueSerializationInfo))
109+
{
110+
keyElementName = keySerializationInfo.ElementName;
111+
valueElementName = valueSerializationInfo.ElementName;
112+
keySerializer = keySerializationInfo.Serializer;
113+
valueSerializer = valueSerializationInfo.Serializer;
114+
return true;
115+
}
116+
117+
keyElementName = null;
118+
valueElementName = null;
119+
keySerializer = null;
120+
valueSerializer = null;
121+
return false;
122+
}
83123
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NewKeyValuePairExpressionToAggregationExpressionTranslator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public static TranslatedExpression Translate(
5252
return new TranslatedExpression(expression, ast, serializer);
5353
}
5454

55-
private static IBsonSerializer CreateResultSerializer(
55+
public static IBsonSerializer CreateResultSerializer(
5656
Type resultType,
5757
IBsonSerializer keySerializer,
5858
IBsonSerializer valueSerializer,

tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp4957Tests.cs

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public void New_array_with_two_items_should_work()
8484

8585
[Theory]
8686
[ParameterAttributeData]
87-
public void New_array_with_two_items_with_different_serializers_should_throw(
87+
public void New_array_with_two_items_with_different_serializers_should_work(
8888
[Values(false, true)] bool enableClientSideProjections)
8989
{
9090
RequireServer.Check().Supports(Feature.FindProjectionExpressions);
@@ -94,21 +94,11 @@ public void New_array_with_two_items_with_different_serializers_should_throw(
9494
var queryable = collection.AsQueryable(translationOptions)
9595
.Select(x => new[] { x.X, x.Y });
9696

97-
if (enableClientSideProjections)
98-
{
99-
var stages = Translate(collection, queryable, out var outputSerializer);
100-
AssertStages(stages, "{ $project : { _snippets : ['$X', '$Y'], _id : 0 } }");
101-
outputSerializer.Should().BeAssignableTo<IClientSideProjectionDeserializer>();
102-
103-
var result = queryable.Single();
104-
result.Should().Equal(1, 2);
105-
}
106-
else
107-
{
108-
var exception = Record.Exception(() => Translate(collection, queryable));
109-
exception.Should().BeOfType<ExpressionNotSupportedException>();
110-
exception.Message.Should().Contain("all items in the array must be serialized using the same serializer");
111-
}
97+
var stages = Translate(collection, queryable, out var outputSerializer);
98+
AssertStages(stages, "{ $project : { _v : ['$X', '$Y'], _id : 0 } }");
99+
100+
var result = queryable.Single();
101+
result.Should().Equal(1, 2);
112102
}
113103

114104
public class C

0 commit comments

Comments
 (0)