Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,30 @@ public interface IKeyValuePairSerializer
BsonType Representation { get; }
}

/// <summary>
/// Static factory class for KeyValuePairSerializers.
/// </summary>
public static class KeyValuePairSerializer
{
/// <summary>
/// Creates a KeyValuePairSerializer.
/// </summary>
/// <param name="representation">The representation.</param>
/// <param name="keySerializer">The key serializer.</param>
/// <param name="valueSerializer">The value Serializer.</param>
/// <returns>A KeyValuePairSerializer.</returns>
public static IBsonSerializer Create(
BsonType representation,
IBsonSerializer keySerializer,
IBsonSerializer valueSerializer)
{
var keyType = keySerializer.ValueType;
var valueType = valueSerializer.ValueType;
var keyValuePairSerializerType = typeof(KeyValuePairSerializer<,>).MakeGenericType(keyType, valueType);
return (IBsonSerializer)Activator.CreateInstance(keyValuePairSerializerType, [representation, keySerializer, valueSerializer]);
}
}

/// <summary>
/// Represents a serializer for KeyValuePairs.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Driver.Linq.Linq3Implementation.Ast.Expressions;

namespace MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators
Expand All @@ -43,37 +45,16 @@ public static TranslatedExpression Translate(
var keyTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, keyExpression);
var valueTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, valueExpression);

var serializer = CreateResultSerializer(expression.Type, keyTranslation.Serializer, valueTranslation.Serializer, out var keyElementName, out var valueElementName);
var ast = AstExpression.ComputedDocument([
AstExpression.ComputedField(keyElementName, keyTranslation.Ast),
AstExpression.ComputedField(valueElementName, valueTranslation.Ast)
AstExpression.ComputedField("k", keyTranslation.Ast),
AstExpression.ComputedField("v", valueTranslation.Ast)
]);

return new TranslatedExpression(expression, ast, serializer);
}

private static IBsonSerializer CreateResultSerializer(
Type resultType,
IBsonSerializer keySerializer,
IBsonSerializer valueSerializer,
out string keyElementName,
out string valueElementName)
{
var constructorInfo = resultType.GetConstructor([keySerializer.ValueType, valueSerializer.ValueType]);
var classMap = new BsonClassMap(resultType);
classMap.MapConstructor(constructorInfo);
classMap.AutoMap();
var keyMemberMap = classMap.GetMemberMap("Key");
keyElementName = keyMemberMap.ElementName;
keyMemberMap.SetSerializer(keySerializer);
var valueMemberMap = classMap.GetMemberMap("Value");
valueElementName = valueMemberMap.ElementName;
valueMemberMap.SetSerializer(valueSerializer);
classMap.Freeze();
var keySerializer = keyTranslation.Serializer;
var valueSerializer = valueTranslation.Serializer;
var keyValuePairSerializer = KeyValuePairSerializer.Create(BsonType.Document, keySerializer, valueSerializer);

// have to use BsonClassMapSerializer here to mimic the MemberInitExpressionToAggregationExpressionTranslator to avoid risking a behavioral breaking change
var serializerType = typeof(BsonClassMapSerializer<>).MakeGenericType(resultType);
return (IBsonSerializer)Activator.CreateInstance(serializerType, classMap);
return new TranslatedExpression(expression, ast, keyValuePairSerializer);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public void Projection_of_ArrayOfDocuments_dictionary_keys_and_values_should_wor
stages,
"{ $match : { ParentId : { $in : [1, 2, 3] }, Gender : 'Male' } }",
"{ $group : { _id : '$ParentId', _elements : { $push : '$$ROOT' } } }",
"{ $project : { Key : '$_id', Value : '$_elements', _id : 0 } }");
"{ $project : { k : '$_id', v : '$_elements', _id : 0 } }");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not call this a breaking change because it doesn't affect the results of the LINQ query.


var results = aggregate.ToList().OrderBy(x => x.Key).ToList();
results[0].Key.Should().Be(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public void NewKeyValuePair_should_translate()
.Select(d => new KeyValuePair<string,int>("X", d.X));

var stages = Translate(collection, queryable);
AssertStages(stages, "{ $project : { Key : 'X', Value : '$X', _id : 0 } }");
AssertStages(stages, "{ $project : { k : 'X', v : '$X', _id : 0 } }");

var result = queryable.Single();
result.Key.Should().Be("X");
Expand All @@ -54,7 +54,7 @@ public void KeyValuePair_Create_should_translate()
.Select(d => KeyValuePair.Create("X", d.X));

var stages = Translate(collection, queryable);
AssertStages(stages, "{ $project : { Key : 'X', Value : '$X', _id : 0 } }");
AssertStages(stages, "{ $project : { k : 'X', v : '$X', _id : 0 } }");

var result = queryable.Single();
result.Key.Should().Be("X");
Expand Down