Skip to content

Commit 15113ca

Browse files
committed
CSHARP-5779: Added tests for dictionaries with nested dictionary values
1 parent 40372f3 commit 15113ca

File tree

2 files changed

+119
-5
lines changed

2 files changed

+119
-5
lines changed

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/SelectManyMethodToAggregationExpressionTranslator.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
using MongoDB.Driver.Linq.Linq3Implementation.Ast.Expressions;
2020
using MongoDB.Driver.Linq.Linq3Implementation.Misc;
2121
using MongoDB.Driver.Linq.Linq3Implementation.Reflection;
22+
using MongoDB.Driver.Linq.Linq3Implementation.Serializers;
2223

2324
namespace MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MethodTranslators
2425
{
@@ -47,6 +48,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC
4748
var selectorParameterSymbol = context.CreateSymbol(selectorParameter, selectorParameterSerializer);
4849
var selectorContext = context.WithSymbol(selectorParameterSymbol);
4950
var selectorTranslation = ExpressionToAggregationExpressionTranslator.Translate(selectorContext, selectorLambda.Body);
51+
var itemSerializer = ArraySerializerHelper.GetItemSerializer(selectorTranslation.Serializer);
5052

5153
var asVar = selectorParameterSymbol.Var;
5254
var valueVar = AstExpression.Var("value");
@@ -59,7 +61,8 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC
5961
initialValue: new BsonArray(),
6062
@in: AstExpression.ConcatArrays(valueVar, thisVar));
6163

62-
return new TranslatedExpression(expression, ast, selectorTranslation.Serializer);
64+
var ienumerableSerializer = IEnumerableSerializer.Create(itemSerializer);
65+
return new TranslatedExpression(expression, ast, ienumerableSerializer);
6366
}
6467

6568
throw new ExpressionNotSupportedException(expression);

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

Lines changed: 115 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,29 @@
1717
using System.Linq;
1818
using MongoDB.Driver.TestHelpers;
1919
using FluentAssertions;
20+
using MongoDB.Bson.Serialization;
2021
using MongoDB.Bson.Serialization.Attributes;
2122
using MongoDB.Bson.Serialization.Options;
23+
using MongoDB.Bson.Serialization.Serializers;
24+
using MongoDB.Driver.Linq.Linq3Implementation.Serializers;
2225
using Xunit;
2326

2427
namespace MongoDB.Driver.Tests.Linq.Linq3Implementation.Jira;
2528

2629
public class CSharp5779Tests : LinqIntegrationTest<CSharp5779Tests.ClassFixture>
2730
{
31+
static CSharp5779Tests()
32+
{
33+
BsonClassMap.RegisterClassMap<C>(cm =>
34+
{
35+
cm.AutoMap();
36+
37+
var innerDictionarySerializer = DictionarySerializer.Create(DictionaryRepresentation.ArrayOfArrays, StringSerializer.Instance, Int32Serializer.Instance);
38+
var outerDictionarySerializer = DictionarySerializer.Create(DictionaryRepresentation.Document, StringSerializer.Instance, innerDictionarySerializer);
39+
cm.MapMember(c => c.DictionaryAsDocumentOfNestedDictionaryAsArrayOfArrays).SetSerializer(outerDictionarySerializer);
40+
});
41+
}
42+
2843
public CSharp5779Tests(ClassFixture fixture)
2944
: base(fixture)
3045
{
@@ -486,6 +501,82 @@ public void IDictionaryAsDocument_Values_First_with_predicate_should_work()
486501
results[3].Should().Be(2);
487502
}
488503

504+
[Fact]
505+
public void DictionaryAsDocumentOfNestedDictionaryAsArrayOfArrays_Values_SelectMany_Keys_should_work()
506+
{
507+
var collection = Fixture.Collection;
508+
509+
var queryable = collection.AsQueryable()
510+
.Select(x => x.DictionaryAsDocumentOfNestedDictionaryAsArrayOfArrays.Values.SelectMany(n => n.Keys));
511+
512+
var stages = Translate(collection, queryable);
513+
AssertStages(stages, "{ $project : { _v : { $reduce : { input : { $map : { input : { $objectToArray : '$DictionaryAsDocumentOfNestedDictionaryAsArrayOfArrays' }, as : 'n', in : { $map : { input : '$$n.v', as : 'kvp', in : { $arrayElemAt : ['$$kvp', 0] } } } } }, initialValue : [], in : { $concatArrays : ['$$value', '$$this'] } } }, _id : 0 } }");
514+
515+
var results = queryable.ToList();
516+
results.Count.Should().Be(4);
517+
results[0].Should().Equal();
518+
results[1].Should().Equal("a");
519+
results[2].Should().Equal("a", "a", "b");
520+
results[3].Should().Equal("a", "a", "b", "a", "b", "c");
521+
}
522+
523+
[Fact]
524+
public void DictionaryAsDocumentOfNestedDictionaryAsArrayOfArrays_Values_SelectMany_Keys_Where_should_work()
525+
{
526+
var collection = Fixture.Collection;
527+
528+
var queryable = collection.AsQueryable()
529+
.Select(x => x.DictionaryAsDocumentOfNestedDictionaryAsArrayOfArrays.Values.SelectMany(n => n.Keys.Where(k => k != "a")));
530+
531+
var stages = Translate(collection, queryable);
532+
AssertStages(stages, "{ $project : { _v : { $reduce : { input : { $map : { input : { $objectToArray : '$DictionaryAsDocumentOfNestedDictionaryAsArrayOfArrays' }, as : 'n', in : { $filter : { input : { $map : { input : '$$n.v', as : 'kvp', in : { $arrayElemAt : ['$$kvp', 0] } } }, as : 'k', cond : { $ne : ['$$k', 'a'] } } } } }, initialValue : [], in : { $concatArrays : ['$$value', '$$this'] } } }, _id : 0 } }");
533+
534+
var results = queryable.ToList();
535+
results.Count.Should().Be(4);
536+
results[0].Should().Equal();
537+
results[1].Should().Equal();
538+
results[2].Should().Equal("b");
539+
results[3].Should().Equal("b", "b", "c");
540+
}
541+
542+
[Fact]
543+
public void DictionaryAsDocumentOfNestedDictionaryAsArrayOfArrays_Values_SelectMany_Values_should_work()
544+
{
545+
var collection = Fixture.Collection;
546+
547+
var queryable = collection.AsQueryable()
548+
.Select(x => x.DictionaryAsDocumentOfNestedDictionaryAsArrayOfArrays.Values.SelectMany(n => n.Values));
549+
550+
var stages = Translate(collection, queryable);
551+
AssertStages(stages, "{ $project : { _v : { $reduce : { input : { $map : { input : { $objectToArray : '$DictionaryAsDocumentOfNestedDictionaryAsArrayOfArrays' }, as : 'n', in : { $map : { input : '$$n.v', as : 'kvp', in : { k : { $arrayElemAt : ['$$kvp', 0] }, v : { $arrayElemAt : ['$$kvp', 1] } } } } } }, initialValue : [], in : { $concatArrays : ['$$value', '$$this'] } } }, _id : 0 } }");
552+
553+
var results = queryable.ToList();
554+
results.Count.Should().Be(4);
555+
results[0].Should().Equal();
556+
results[1].Should().Equal(1);
557+
results[2].Should().Equal(1, 1, 2);
558+
results[3].Should().Equal(1, 1, 2, 1, 2, 3);
559+
}
560+
561+
[Fact]
562+
public void DictionaryAsDocumentOfNestedDictionaryAsArrayOfArrays_Values_SelectMany_Values_Where_should_work()
563+
{
564+
var collection = Fixture.Collection;
565+
566+
var queryable = collection.AsQueryable()
567+
.Select(x => x.DictionaryAsDocumentOfNestedDictionaryAsArrayOfArrays.Values.SelectMany(n => n.Values.Where(v => v > 1)));
568+
569+
var stages = Translate(collection, queryable);
570+
AssertStages(stages, "{ $project : { _v : { $reduce : { input : { $map : { input : { $objectToArray : '$DictionaryAsDocumentOfNestedDictionaryAsArrayOfArrays' }, as : 'n', in : { $filter : { input : { $map : { input : '$$n.v', as : 'kvp', in : { k : { $arrayElemAt : ['$$kvp', 0] }, v : { $arrayElemAt : ['$$kvp', 1] } } } }, as : 'v', cond : { $gt : ['$$v.v', 1] } } } } }, initialValue : [], in : { $concatArrays : ['$$value', '$$this'] } } }, _id : 0 } }");
571+
572+
var results = queryable.ToList();
573+
results.Count.Should().Be(4);
574+
results[0].Should().Equal();
575+
results[1].Should().Equal();
576+
results[2].Should().Equal(2);
577+
results[3].Should().Equal(2, 2, 3);
578+
}
579+
489580
public class C
490581
{
491582
public int Id { get; set; }
@@ -495,6 +586,7 @@ public class C
495586
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] public IDictionary<string, int> IDictionaryAsArrayOfArrays { get; set; }
496587
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfDocuments)] public IDictionary<string, int> IDictionaryAsArrayOfDocuments { get; set; }
497588
[BsonDictionaryOptions(DictionaryRepresentation.Document)] public IDictionary<string, int> IDictionaryAsDocument { get; set; }
589+
public Dictionary<string, Dictionary<string, int>> DictionaryAsDocumentOfNestedDictionaryAsArrayOfArrays { get; set; }
498590
}
499591

500592
public sealed class ClassFixture : MongoCollectionFixture<C>
@@ -509,7 +601,8 @@ public sealed class ClassFixture : MongoCollectionFixture<C>
509601
DictionaryAsDocument = new Dictionary<string, int>(),
510602
IDictionaryAsArrayOfArrays = new Dictionary<string, int>(),
511603
IDictionaryAsArrayOfDocuments = new Dictionary<string, int>(),
512-
IDictionaryAsDocument = new Dictionary<string, int>()
604+
IDictionaryAsDocument = new Dictionary<string, int>(),
605+
DictionaryAsDocumentOfNestedDictionaryAsArrayOfArrays = new Dictionary<string, Dictionary<string, int>>()
513606
},
514607
new C
515608
{
@@ -519,7 +612,12 @@ public sealed class ClassFixture : MongoCollectionFixture<C>
519612
DictionaryAsDocument = new Dictionary<string, int> { { "a", 1 } },
520613
IDictionaryAsArrayOfArrays = new Dictionary<string, int> { { "a", 1 } },
521614
IDictionaryAsArrayOfDocuments = new Dictionary<string, int> { { "a", 1 } },
522-
IDictionaryAsDocument = new Dictionary<string, int> { { "a", 1 } }
615+
IDictionaryAsDocument = new Dictionary<string, int> { { "a", 1 } },
616+
DictionaryAsDocumentOfNestedDictionaryAsArrayOfArrays = new Dictionary<string, Dictionary<string, int>>
617+
{
618+
{ "", new Dictionary<string, int>() },
619+
{ "a", new Dictionary<string, int> { { "a", 1 } } }
620+
}
523621
},
524622
new C
525623
{
@@ -529,7 +627,13 @@ public sealed class ClassFixture : MongoCollectionFixture<C>
529627
DictionaryAsDocument = new Dictionary<string, int> { { "a", 1 }, { "b", 2 } },
530628
IDictionaryAsArrayOfArrays = new Dictionary<string, int> { { "a", 1 }, { "b", 2 } },
531629
IDictionaryAsArrayOfDocuments = new Dictionary<string, int> { { "a", 1 }, { "b", 2 } },
532-
IDictionaryAsDocument = new Dictionary<string, int> { { "a", 1 }, { "b", 2 }, }
630+
IDictionaryAsDocument = new Dictionary<string, int> { { "a", 1 }, { "b", 2 }, },
631+
DictionaryAsDocumentOfNestedDictionaryAsArrayOfArrays = new Dictionary<string, Dictionary<string, int>>
632+
{
633+
{ "", new Dictionary<string, int>() },
634+
{ "a", new Dictionary<string, int> { { "a", 1 } } },
635+
{ "b", new Dictionary<string, int> { { "a", 1 }, { "b", 2 } } }
636+
}
533637
},
534638
new C
535639
{
@@ -539,7 +643,14 @@ public sealed class ClassFixture : MongoCollectionFixture<C>
539643
DictionaryAsDocument = new Dictionary<string, int> { { "a", 1 }, { "b", 2 }, { "c", 3 } },
540644
IDictionaryAsArrayOfArrays = new Dictionary<string, int> { { "a", 1 }, { "b", 2 }, { "c", 3 } },
541645
IDictionaryAsArrayOfDocuments = new Dictionary<string, int> { { "a", 1 }, { "b", 2 }, { "c", 3 } },
542-
IDictionaryAsDocument = new Dictionary<string, int> { { "a", 1 }, { "b", 2 }, { "c", 3 } }
646+
IDictionaryAsDocument = new Dictionary<string, int> { { "a", 1 }, { "b", 2 }, { "c", 3 } },
647+
DictionaryAsDocumentOfNestedDictionaryAsArrayOfArrays = new Dictionary<string, Dictionary<string, int>>
648+
{
649+
{ "", new Dictionary<string, int>() },
650+
{ "a", new Dictionary<string, int> { { "a", 1 } } },
651+
{ "b", new Dictionary<string, int> { { "a", 1 }, { "b", 2 } } },
652+
{ "c", new Dictionary<string, int> { { "a", 1 }, { "b", 2 }, { "c", 3 } } }
653+
}
543654
},
544655
];
545656
}

0 commit comments

Comments
 (0)