Skip to content

Commit 02150af

Browse files
committed
Work in progress.
1 parent a61c243 commit 02150af

File tree

9 files changed

+98
-48
lines changed

9 files changed

+98
-48
lines changed

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

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,30 +108,34 @@ private void DeduceBooleanSerializer(Expression node)
108108
}
109109
}
110110

111-
private void DeduceCollectionAndItemSerializers(Expression collectionExpression, Expression itemExpression)
112-
{
113-
DeduceItemAndCollectionSerializers(itemExpression, collectionExpression);
114-
}
115-
116111
private void DeduceCollectionAndCollectionSerializers(Expression collectionExpression1, Expression collectionExpression2)
117112
{
118113
IBsonSerializer collectionSerializer1;
119114
IBsonSerializer collectionSerializer2;
120115

121116
if (IsNotKnown(collectionExpression1) && IsKnown(collectionExpression2, out collectionSerializer2))
122117
{
123-
collectionSerializer1 = CreateCollectionSerializerFromCollectionSerializer(collectionExpression1.Type, collectionSerializer2);
118+
collectionSerializer1 = collectionSerializer2 is IUnknowableSerializer ?
119+
UnknowableSerializer.Create(collectionExpression1.Type) :
120+
CreateCollectionSerializerFromCollectionSerializer(collectionExpression1.Type, collectionSerializer2);
124121
AddKnownSerializer(collectionExpression1, collectionSerializer1);
125122
}
126123

127124
if (IsNotKnown(collectionExpression2) && IsKnown(collectionExpression1, out collectionSerializer1))
128125
{
129-
collectionSerializer2 = CreateCollectionSerializerFromCollectionSerializer(collectionExpression2.Type, collectionSerializer1);
126+
collectionSerializer2 = collectionSerializer1 is IUnknowableSerializer ?
127+
UnknowableSerializer.Create(collectionExpression2.Type) :
128+
CreateCollectionSerializerFromCollectionSerializer(collectionExpression2.Type, collectionSerializer1);
130129
AddKnownSerializer(collectionExpression2, collectionSerializer2);
131130
}
132131

133132
}
134133

134+
private void DeduceCollectionAndItemSerializers(Expression collectionExpression, Expression itemExpression)
135+
{
136+
DeduceItemAndCollectionSerializers(itemExpression, collectionExpression);
137+
}
138+
135139
private void DeduceItemAndCollectionSerializers(Expression itemExpression, Expression collectionExpression)
136140
{
137141
if (IsNotKnown(itemExpression) && IsItemSerializerKnown(collectionExpression, out var itemSerializer))
@@ -141,7 +145,9 @@ private void DeduceItemAndCollectionSerializers(Expression itemExpression, Expre
141145

142146
if (IsNotKnown(collectionExpression) && IsKnown(itemExpression, out itemSerializer))
143147
{
144-
var collectionSerializer = CreateCollectionSerializerFromItemSerializer(collectionExpression.Type, itemSerializer);
148+
var collectionSerializer = itemSerializer is IUnknowableSerializer ?
149+
UnknowableSerializer.Create(collectionExpression.Type) :
150+
CreateCollectionSerializerFromItemSerializer(collectionExpression.Type, itemSerializer);
145151
if (collectionSerializer != null)
146152
{
147153
AddKnownSerializer(collectionExpression, collectionSerializer);
@@ -178,6 +184,15 @@ private void DeduceStringSerializer(Expression node)
178184
}
179185
}
180186

187+
private void DeduceUnknowableSerializer(Expression node)
188+
{
189+
if (IsNotKnown(node))
190+
{
191+
var unknowableSerializer = UnknowableSerializer.Create(node.Type);
192+
AddKnownSerializer(node, unknowableSerializer);
193+
}
194+
}
195+
181196
private bool IsItemSerializerKnown(Expression node, out IBsonSerializer itemSerializer)
182197
{
183198
if (IsKnown(node, out var serializer) &&

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,11 @@ protected override Expression VisitBinary(BinaryExpression node)
4242
if (IsSymmetricalBinaryOperator(@operator) &&
4343
CanDeduceSerializer(leftExpression, rightExpression, out var unknownNode, out var knownSerializer))
4444
{
45-
var isNull = unknownNode is ConstantExpression { Value: null };
46-
if (!isNull && unknownNode.Type != knownSerializer.ValueType)
45+
// expr1 op expr2 => expr1: expr2Serializer or expr2: expr1Serializer
46+
if (knownSerializer.ValueType == unknownNode.Type)
4747
{
48-
throw new ExpressionNotSupportedException(node, because: "operand types are not compatible with each other");
48+
AddKnownSerializer(unknownNode, knownSerializer);
4949
}
50-
51-
// expr1 op expr2 => expr1: expr2Serializer or expr2: expr1Serializer
52-
AddKnownSerializer(unknownNode, knownSerializer);
5350
}
5451

5552
if (@operator == ExpressionType.ArrayIndex)

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

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -654,25 +654,11 @@ protected override Expression VisitMethodCall(MethodCallExpression node)
654654
var arguments = node.Arguments;
655655

656656
DeduceMethodCallSerializers();
657-
try
657+
if (IsKnown(node, out var knownSerializer) && knownSerializer is IUnknowableSerializer)
658658
{
659-
base.VisitMethodCall(node);
660-
}
661-
catch
662-
{
663-
if (node.Method.Is(QueryableMethod.Select) && (_translationOptions.EnableClientSideProjections ?? false))
664-
{
665-
var sourceExpression = arguments[0];
666-
if (IsItemSerializerKnown(sourceExpression, out var sourceItemSerializer))
667-
{
668-
AddKnownSerializer(node, IgnoreSubtreeSerializer.Create(node.Type));
669-
}
670-
}
671-
else
672-
{
673-
throw;
674-
}
659+
return node; // don't visit node any further
675660
}
661+
base.VisitMethodCall(node);
676662
DeduceMethodCallSerializers();
677663

678664
return node;
@@ -840,7 +826,8 @@ void DeduceMethodCallSerializers()
840826
break;
841827

842828
default:
843-
throw new ExpressionNotSupportedException(node, because: $"method {method.Name} is not supported");
829+
DeduceUnknowableSerializer(node);
830+
break;
844831
}
845832
}
846833

@@ -2187,8 +2174,10 @@ void DeduceReturnsOneSourceItemSerializer()
21872174

21882175
if (IsNotKnown(node) && IsKnown(sourceExpression, out var sourceSerializer))
21892176
{
2190-
var sourceItemSerializer = ArraySerializerHelper.GetItemSerializer(sourceSerializer);
2191-
AddKnownSerializer(node, sourceItemSerializer);
2177+
var nodeSerializer = sourceSerializer is IUnknowableSerializer ?
2178+
UnknowableSerializer.Create(node.Type) :
2179+
ArraySerializerHelper.GetItemSerializer(sourceSerializer);
2180+
AddKnownSerializer(node, nodeSerializer);
21922181
}
21932182
}
21942183

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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -192,11 +192,11 @@ static IBsonSerializer GetConvertEnumToEnumSerializer(UnaryExpression expression
192192
throw new ExpressionNotSupportedException(expression, because: "target type is not an enum");
193193
}
194194

195-
if (sourceSerializer is IHasRepresentationSerializer sourceHasRepresentationSerializer &&
196-
!SerializationHelper.IsNumericRepresentation(sourceHasRepresentationSerializer.Representation))
197-
{
198-
throw new ExpressionNotSupportedException(expression, because: "source enum is not represented as a number");
199-
}
195+
// if (sourceSerializer is IHasRepresentationSerializer sourceHasRepresentationSerializer &&
196+
// !SerializationHelper.IsNumericRepresentation(sourceHasRepresentationSerializer.Representation))
197+
// {
198+
// throw new ExpressionNotSupportedException(expression, because: "source enum is not represented as a number");
199+
// }
200200

201201
return EnumSerializer.Create(targetType);
202202
}
@@ -214,17 +214,17 @@ static IBsonSerializer GetConvertFromNullableTypeSerializer(UnaryExpression expr
214214
throw new ExpressionNotSupportedException(expression, because: $"sourceSerializer type {sourceSerializer.GetType()} does not implement nameof(INullableSerializer)");
215215
}
216216

217-
var valueSerializer = nullableSourceSerializer.ValueSerializer;
217+
var sourceValueSerializer = nullableSourceSerializer.ValueSerializer;
218+
var sourceValueType = sourceValueSerializer.ValueType;
219+
218220
if (targetType.IsNullable(out var targetValueType))
219221
{
220-
var sourceValueSerializer = nullableSourceSerializer.ValueSerializer;
221-
var sourceValueType = sourceValueSerializer.ValueType;
222222
var targetValueSerializer = GetTargetSerializer(expression, sourceValueType, targetValueType, sourceValueSerializer);
223223
return NullableSerializer.Create(targetValueSerializer);
224224
}
225225
else
226226
{
227-
return valueSerializer;
227+
return GetTargetSerializer(expression, sourceValueType, targetType, sourceValueSerializer);
228228
}
229229
}
230230

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,12 @@ public KnownSerializerFinderVisitor(ExpressionTranslationOptions translationOpti
4141

4242
public override Expression Visit(Expression node)
4343
{
44-
if (IsKnown(node, out var knownSerializer) && knownSerializer is IIgnoreSubtreeSerializer)
44+
if (IsKnown(node, out var knownSerializer))
4545
{
46-
return node; // don't visit subtree
46+
if (knownSerializer is IIgnoreSubtreeSerializer or IUnknowableSerializer)
47+
{
48+
return node; // don't visit subtree
49+
}
4750
}
4851

4952
return base.Visit(node);

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,12 @@ public UnknownSerializerFinder(KnownSerializerMap knownSerializers)
4141

4242
public override Expression Visit(Expression node)
4343
{
44-
if (_knownSerializers.IsKnown(node, out var knownSerializer) && knownSerializer is IIgnoreSubtreeSerializer)
44+
if (_knownSerializers.IsKnown(node, out var knownSerializer))
4545
{
46-
return node; // don't visit subtree
46+
if (knownSerializer is IIgnoreSubtreeSerializer or IUnknowableSerializer)
47+
{
48+
return node; // don't visit subtree
49+
}
4750
}
4851

4952
base.Visit(node);

src/MongoDB.Driver/Linq/Linq3Implementation/Serializers/NumericConversionSerializer.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ private object Convert(Type from, Type to, object value)
6969
{
7070
(TypeCode.Decimal, TypeCode.Double) => (object)(double)(decimal)value,
7171
(TypeCode.Double, TypeCode.Decimal) => (object)(decimal)(double)value,
72+
(TypeCode.Int16, TypeCode.Int32) => (object)(int)(short)value,
73+
(TypeCode.Int16, TypeCode.Int64) => (object)(long)(short)value,
74+
(TypeCode.Int32, TypeCode.Int16) => (object)(short)(int)value,
75+
(TypeCode.Int32, TypeCode.Int64) => (object)(long)(int)value,
76+
(TypeCode.Int64, TypeCode.Int16) => (object)(short)(long)value,
77+
(TypeCode.Int64, TypeCode.Int32) => (object)(int)(long)value,
7278
_ => throw new NotSupportedException($"Cannot convert {from} to {to}"),
7379
};
7480
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using System;
17+
using MongoDB.Bson.Serialization;
18+
using MongoDB.Bson.Serialization.Serializers;
19+
20+
namespace MongoDB.Driver.Linq.Linq3Implementation.Serializers;
21+
22+
internal static class UnknowableSerializer
23+
{
24+
public static IBsonSerializer Create(Type valueType)
25+
{
26+
var serializerType = typeof(UnknowableSerializer<>).MakeGenericType(valueType);
27+
return (IBsonSerializer)Activator.CreateInstance(serializerType);
28+
}
29+
}
30+
31+
internal interface IUnknowableSerializer
32+
{
33+
}
34+
35+
internal class UnknowableSerializer<TValue> : SerializerBase<TValue>, IUnknowableSerializer
36+
{
37+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public static TranslatedExpression TranslateWithKnownSerializer(
4646
var argumentTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, argument);
4747
var matchingMemberSerializationInfo = matchingMemberSerializationInfos[i];
4848

49-
if (!argumentTranslation.Serializer.Equals(matchingMemberSerializationInfo.Serializer))
49+
if (!argumentTranslation.Serializer.CanBeAssignedTo(matchingMemberSerializationInfo.Serializer))
5050
{
5151
throw new ExpressionNotSupportedException(argument, expression, because: "argument serializer is not equal to member serializer");
5252
}

0 commit comments

Comments
 (0)