Skip to content

Commit 205eb56

Browse files
committed
rebase on main for keys and values work from robert
1 parent 462dc1c commit 205eb56

File tree

4 files changed

+51
-199
lines changed

4 files changed

+51
-199
lines changed

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

Lines changed: 10 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,6 @@ public static TranslatedExpression Translate(TranslationContext context, MemberE
7575
return LengthPropertyToAggregationExpressionTranslator.Translate(context, expression);
7676
}
7777

78-
if (TryTranslateDictionaryProperty(expression, containerTranslation, member, out var translatedDictionaryProperty))
79-
{
80-
return translatedDictionaryProperty;
81-
}
82-
8378
if (TryTranslateKeyValuePairProperty(expression, containerTranslation, member, out var translatedKeyValuePairProperty))
8479
{
8580
return translatedKeyValuePairProperty;
@@ -231,6 +226,16 @@ private static bool TryTranslateDictionaryProperty(TranslationContext context, M
231226

232227
switch (propertyInfo.Name)
233228
{
229+
case "Count":
230+
var countAst = dictionaryRepresentation switch
231+
{
232+
DictionaryRepresentation.ArrayOfDocuments or DictionaryRepresentation.ArrayOfArrays => AstExpression.Size(containerAst),
233+
_ => throw new ExpressionNotSupportedException(expression, $"Unexpected dictionary representation: {dictionaryRepresentation}")
234+
};
235+
var countSerializer = Int32Serializer.Instance;
236+
translatedDictionaryProperty = new TranslatedExpression(expression, countAst, countSerializer);
237+
return true;
238+
234239
case "Keys":
235240
var keysAst = dictionaryRepresentation switch
236241
{
@@ -310,110 +315,5 @@ private static bool TryTranslateKeyValuePairProperty(MemberExpression expression
310315

311316
return false;
312317
}
313-
314-
private static bool TryTranslateDictionaryProperty(MemberExpression expression, TranslatedExpression container, MemberInfo memberInfo, out TranslatedExpression result)
315-
{
316-
result = null;
317-
318-
if (memberInfo is PropertyInfo propertyInfo &&
319-
propertyInfo.DeclaringType.IsGenericType &&
320-
(propertyInfo.DeclaringType.GetGenericTypeDefinition() == typeof(Dictionary<,>) ||
321-
propertyInfo.DeclaringType.GetGenericTypeDefinition() == typeof(IDictionary<,>)))
322-
{
323-
if (container.Serializer is IBsonDictionarySerializer dictionarySerializer)
324-
{
325-
switch (propertyInfo.Name)
326-
{
327-
case "Count":
328-
{
329-
AstExpression countAst;
330-
switch (dictionarySerializer.DictionaryRepresentation)
331-
{
332-
case DictionaryRepresentation.Document:
333-
countAst = AstExpression.Size(AstExpression.ObjectToArray(container.Ast));
334-
break;
335-
case DictionaryRepresentation.ArrayOfArrays:
336-
case DictionaryRepresentation.ArrayOfDocuments:
337-
countAst = AstExpression.Size(container.Ast);
338-
break;
339-
default:
340-
throw new ExpressionNotSupportedException(expression);
341-
}
342-
343-
var serializer = Int32Serializer.Instance;
344-
result = new TranslatedExpression(expression, countAst, serializer);
345-
return true;
346-
}
347-
348-
case "Keys":
349-
{
350-
AstExpression keysAst;
351-
switch (dictionarySerializer.DictionaryRepresentation)
352-
{
353-
case DictionaryRepresentation.Document:
354-
keysAst = AstExpression.GetField(AstExpression.ObjectToArray(container.Ast), "k");
355-
break;
356-
case DictionaryRepresentation.ArrayOfArrays:
357-
{
358-
var kvp = AstExpression.Var("kvp");
359-
keysAst = AstExpression.Map(
360-
input: container.Ast,
361-
@as: kvp,
362-
@in: AstExpression.ArrayElemAt(kvp, 0));
363-
break;
364-
}
365-
case DictionaryRepresentation.ArrayOfDocuments:
366-
keysAst = AstExpression.GetField(container.Ast, "k");
367-
break;
368-
369-
default:
370-
throw new ExpressionNotSupportedException(expression);
371-
}
372-
373-
var serializer = ArraySerializerHelper.CreateSerializer(dictionarySerializer.KeySerializer);
374-
result = new TranslatedExpression(expression, keysAst, serializer);
375-
return true;
376-
}
377-
378-
case "Values":
379-
{
380-
AstExpression valuesAst;
381-
switch (dictionarySerializer.DictionaryRepresentation)
382-
{
383-
case DictionaryRepresentation.Document:
384-
valuesAst = AstExpression.GetField(AstExpression.ObjectToArray(container.Ast), "v");
385-
break;
386-
case DictionaryRepresentation.ArrayOfArrays:
387-
{
388-
var kvp = AstExpression.Var("kvp");
389-
valuesAst = AstExpression.Map(
390-
input: container.Ast,
391-
@as: kvp,
392-
@in: AstExpression.ArrayElemAt(kvp, 1));
393-
break;
394-
}
395-
case DictionaryRepresentation.ArrayOfDocuments:
396-
valuesAst = AstExpression.GetField(container.Ast, "v");
397-
break;
398-
399-
default:
400-
throw new ExpressionNotSupportedException(expression);
401-
}
402-
403-
var serializer = ArraySerializerHelper.CreateSerializer(dictionarySerializer.ValueSerializer);
404-
result = new TranslatedExpression(expression, valuesAst, serializer);
405-
return true;
406-
}
407-
408-
default:
409-
throw new ExpressionNotSupportedException(expression);
410-
}
411-
}
412-
413-
throw new ExpressionNotSupportedException(expression, because: "serializer does not implement IBsonDictionarySerializer");
414-
}
415-
416-
return false;
417-
}
418318
}
419319
}

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
using MongoDB.Driver.Linq.Linq3Implementation.Ast.Expressions;
2222
using MongoDB.Driver.Linq.Linq3Implementation.Misc;
2323
using MongoDB.Driver.Linq.Linq3Implementation.Reflection;
24+
using MongoDB.Driver.Linq.Linq3Implementation.Serializers;
2425

2526
namespace MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MethodTranslators
2627
{
@@ -123,7 +124,21 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC
123124
}
124125
else
125126
{
126-
ast = AstExpression.Avg(sourceTranslation.Ast);
127+
var sourceItemSerializer = ArraySerializerHelper.GetItemSerializer(sourceTranslation.Serializer);
128+
if (sourceItemSerializer is IWrappedValueSerializer wrappedValueSerializer)
129+
{
130+
var itemVar = AstExpression.Var("item");
131+
var unwrappedItemAst = AstExpression.GetField(itemVar, wrappedValueSerializer.FieldName);
132+
ast = AstExpression.Avg(
133+
AstExpression.Map(
134+
input: sourceTranslation.Ast,
135+
@as: itemVar,
136+
@in: unwrappedItemAst));
137+
}
138+
else
139+
{
140+
ast = AstExpression.Avg(sourceTranslation.Ast);
141+
}
127142
}
128143
IBsonSerializer serializer = expression.Type switch
129144
{

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

Lines changed: 19 additions & 3 deletions
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
{
@@ -91,9 +92,24 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC
9192
IBsonSerializer serializer;
9293
if (arguments.Count == 1)
9394
{
94-
var array = sourceTranslation.Ast;
95-
ast = method.Name == "Max" ? AstExpression.Max(array) : AstExpression.Min(array);
96-
serializer = ArraySerializerHelper.GetItemSerializer(sourceTranslation.Serializer);
95+
var sourceItemSerializer = ArraySerializerHelper.GetItemSerializer(sourceTranslation.Serializer);
96+
if (sourceItemSerializer is IWrappedValueSerializer wrappedValueSerializer)
97+
{
98+
var itemVar = AstExpression.Var("item");
99+
var unwrappedItemAst = AstExpression.GetField(itemVar, wrappedValueSerializer.FieldName);
100+
var mappedArray = AstExpression.Map(
101+
input: sourceTranslation.Ast,
102+
@as: itemVar,
103+
@in: unwrappedItemAst);
104+
ast = method.Name == "Max" ? AstExpression.Max(mappedArray) : AstExpression.Min(mappedArray);
105+
serializer = wrappedValueSerializer.ValueSerializer;
106+
}
107+
else
108+
{
109+
var array = sourceTranslation.Ast;
110+
ast = method.Name == "Max" ? AstExpression.Max(array) : AstExpression.Min(array);
111+
serializer = sourceItemSerializer;
112+
}
97113
}
98114
else
99115
{

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

Lines changed: 6 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
using MongoDB.Bson;
2020
using MongoDB.Bson.Serialization.Attributes;
2121
using MongoDB.Bson.Serialization.Options;
22-
using MongoDB.Driver.Linq;
2322
using Xunit;
2423

2524
namespace MongoDB.Driver.Tests.Linq.Linq3Implementation.Jira;
@@ -31,84 +30,6 @@ public CSharp4443Tests(ClassFixture fixture)
3130
{
3231
}
3332

34-
[Fact]
35-
public void Projecting_dictionary_keys_with_arrayOfArrays_should_throw()
36-
{
37-
var exception = Record.Exception(() =>
38-
{
39-
_ = Fixture.ArrayOfArraysCollection.AsQueryable()
40-
.Select(x => x.Dictionary.Keys)
41-
.ToList();
42-
});
43-
44-
exception.Should().BeOfType<ExpressionNotSupportedException>();
45-
}
46-
47-
[Fact]
48-
public void Projecting_dictionary_keys_with_arrayOfDocs_should_throw()
49-
{
50-
var exception = Record.Exception(() =>
51-
{
52-
_ = Fixture.ArrayOfDocsCollection.AsQueryable()
53-
.Select(x => x.Dictionary.Keys)
54-
.ToList();
55-
});
56-
57-
exception.Should().BeOfType<ExpressionNotSupportedException>();
58-
}
59-
60-
[Fact]
61-
public void Projecting_dictionary_keys_with_document_should_throw()
62-
{
63-
var exception = Record.Exception(() =>
64-
{
65-
_ = Fixture.DocCollection.AsQueryable()
66-
.Select(x => x.Dictionary.Keys)
67-
.ToList();
68-
});
69-
70-
exception.Should().BeOfType<ExpressionNotSupportedException>();
71-
}
72-
73-
[Fact]
74-
public void Projecting_dictionary_values_with_arrayOfArrays_should_throw()
75-
{
76-
var exception = Record.Exception(() =>
77-
{
78-
_ = Fixture.ArrayOfArraysCollection.AsQueryable()
79-
.Select(x => x.Dictionary.Values)
80-
.ToList();
81-
});
82-
83-
exception.Should().BeOfType<ExpressionNotSupportedException>();
84-
}
85-
86-
[Fact]
87-
public void Projecting_dictionary_values_with_arrayOfDocs_should_throw()
88-
{
89-
var exception = Record.Exception(() =>
90-
{
91-
_ = Fixture.ArrayOfDocsCollection.AsQueryable()
92-
.Select(x => x.Dictionary.Values)
93-
.ToList();
94-
});
95-
96-
exception.Should().BeOfType<ExpressionNotSupportedException>();
97-
}
98-
99-
[Fact]
100-
public void Projecting_dictionary_values_with_document_should_throw()
101-
{
102-
var exception = Record.Exception(() =>
103-
{
104-
_ = Fixture.DocCollection.AsQueryable()
105-
.Select(x => x.Dictionary.Values)
106-
.ToList();
107-
});
108-
109-
exception.Should().BeOfType<ExpressionNotSupportedException>();
110-
}
111-
11233
[Fact]
11334
public void Select_DictionaryAsArrayOfArrays_All_should_work()
11435
{
@@ -148,7 +69,7 @@ public void Select_DictionaryAsArrayOfArrays_Average_should_work()
14869
.Select(x => x.Dictionary.Values.Average());
14970

15071
var stages = Translate(collection, queryable);
151-
AssertStages(stages, "{ $project : { _v : { $avg : { $map : { input : '$Dictionary', as : 'kvp', in : { $arrayElemAt : ['$$kvp', 1] } } } }, _id : 0 } }");
72+
AssertStages(stages, "{ $project : { _v : { $avg : { $map : { input : { $map : { input : '$Dictionary', as : 'kvp', in : { k : { $arrayElemAt : ['$$kvp', 0] }, v : { $arrayElemAt : ['$$kvp', 1] } } } }, as : 'item', in : '$$item.v' } } }, _id : 0 } }");
15273

15374
var results = queryable.ToList();
15475
results.Should().Equal(55.666666666666664, 52.0, 67.5, 165.0);
@@ -283,7 +204,7 @@ public void Select_DictionaryAsArrayOfArrays_Max_should_work()
283204
.Select(x => x.Dictionary.Values.Max());
284205

285206
var stages = Translate(collection, queryable);
286-
AssertStages(stages, "{ $project : { _v : { $max : { $map : { input : '$Dictionary', as : 'kvp', in : { $arrayElemAt : ['$$kvp', 1] } } } }, _id : 0 } }");
207+
AssertStages(stages, "{ $project : { _v : { $max : { $map : { input : { $map : { input : '$Dictionary', as : 'kvp', in : { k : { $arrayElemAt : ['$$kvp', 0] }, v : { $arrayElemAt : ['$$kvp', 1] } } } }, as : 'item', in : '$$item.v' } } }, _id : 0 } }");
287208

288209
var results = queryable.ToList();
289210
results.Should().Equal(100, 85, 100, 200);
@@ -632,7 +553,7 @@ public void Select_DictionaryAsDocument_Average_should_work()
632553
.Select(x => x.Dictionary.Values.Average());
633554

634555
var stages = Translate(collection, queryable);
635-
AssertStages(stages, "{ $project : { _v : { $avg : { $let : { vars : { this : { $objectToArray : '$Dictionary' } }, in : '$$this.v' } } }, _id : 0 } }");
556+
AssertStages(stages, "{ $project : { _v : { $avg : { $map : { input : { $objectToArray : '$Dictionary' }, as : 'item', in : '$$item.v' } } }, _id : 0 } }");
636557

637558
var results = queryable.ToList();
638559
results.Should().Equal(55.666666666666664, 52.0, 67.5, 165.0);
@@ -767,7 +688,7 @@ public void Select_DictionaryAsDocument_Max_should_work()
767688
.Select(x => x.Dictionary.Values.Max());
768689

769690
var stages = Translate(collection, queryable);
770-
AssertStages(stages, "{ $project : { _v : { $max : { $let : { vars : { this : { $objectToArray : '$Dictionary' } }, in : '$$this.v' } } }, _id : 0 } }");
691+
AssertStages(stages, "{ $project : { _v : { $max : { $map : { input : { $objectToArray : '$Dictionary' }, as : 'item', in : '$$item.v' } } }, _id : 0 } }");
771692

772693
var results = queryable.ToList();
773694
results.Should().Equal(100, 85, 100, 200);
@@ -1328,7 +1249,7 @@ public void Select_IDictionaryAsDocument_Average_should_work()
13281249
.Select(x => x.DictionaryInterface.Values.Average());
13291250

13301251
var stages = Translate(collection, queryable);
1331-
AssertStages(stages, "{ $project : { _v : { $avg : { $let : { vars : { this : { $objectToArray : '$DictionaryInterface' } }, in : '$$this.v' } } }, _id : 0 } }");
1252+
AssertStages(stages, "{ $project : { _v : { $avg : { $map : { input : { $objectToArray : '$DictionaryInterface' }, as : 'kvp', in : '$$kvp.v' } } }, _id : 0 } }");
13321253

13331254
var results = queryable.ToList();
13341255
results.Should().Equal(55.666666666666664, 52.0, 67.5, 165.0);
@@ -1448,7 +1369,7 @@ public void Select_IDictionaryAsDocument_Max_should_work()
14481369
.Select(x => x.DictionaryInterface.Values.Max());
14491370

14501371
var stages = Translate(collection, queryable);
1451-
AssertStages(stages, "{ $project : { _v : { $max : { $let : { vars : { this : { $objectToArray : '$DictionaryInterface' } }, in : '$$this.v' } } }, _id : 0 } }");
1372+
AssertStages(stages, "{ $project : { _v : { $max : { $map : { input : { $objectToArray : '$DictionaryInterface' }, as : 'kvp', in : '$$kvp.v' } } }, _id : 0 } }");
14521373

14531374
var results = queryable.ToList();
14541375
results.Should().Equal(100, 85, 100, 200);

0 commit comments

Comments
 (0)