Skip to content

Commit 9a6b84e

Browse files
committed
stash
1 parent 81bb360 commit 9a6b84e

25 files changed

+251
-267
lines changed

src/MongoDB.Bson/Serialization/Serializers/ArraySerializer.cs

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

16+
using System;
1617
using System.Collections.Generic;
1718

1819
namespace MongoDB.Bson.Serialization.Serializers
1920
{
21+
/// <summary>
22+
/// A static factory class for ArraySerializers.
23+
/// </summary>
24+
public static class ArraySerializer
25+
{
26+
/// <summary>
27+
/// Creates an ArraySerializer.
28+
/// </summary>
29+
/// <param name="itemSerializer">The item serializer.</param>
30+
/// <returns>An ArraySerializer.</returns>
31+
public static IBsonSerializer Create(IBsonSerializer itemSerializer)
32+
{
33+
var itemType = itemSerializer.ValueType;
34+
var arraySerializerType = typeof(ArraySerializer<>).MakeGenericType(itemType);
35+
return (IBsonSerializer)Activator.CreateInstance(arraySerializerType, itemSerializer);
36+
}
37+
}
38+
2039
/// <summary>
2140
/// Represents a serializer for one-dimensional arrays.
2241
/// </summary>

src/MongoDB.Bson/Serialization/Serializers/KeyValuePairSerializer.cs

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,15 @@ namespace MongoDB.Bson.Serialization.Serializers
2121
/// <summary>
2222
/// An interface implemented by KeyValuePairSerializer.
2323
/// </summary>
24-
public interface IKeyValuePairSerializer
24+
public interface IKeyValuePairSerializer : IBsonSerializer
2525
{
2626
/// <summary>
27-
///
27+
/// Gets the key element name.
28+
/// </summary>
29+
string KeyElementName { get; }
30+
31+
/// <summary>
32+
/// Gets the key serializer.
2833
/// </summary>
2934
IBsonSerializer KeySerializer { get; }
3035

@@ -34,7 +39,12 @@ public interface IKeyValuePairSerializer
3439
BsonType Representation { get; }
3540

3641
/// <summary>
37-
///
42+
/// Gets the value element name.
43+
/// </summary>
44+
string ValueElementName { get; }
45+
46+
/// <summary>
47+
/// Gets the value serializer.
3848
/// </summary>
3949
IBsonSerializer ValueSerializer { get; }
4050
}
@@ -51,15 +61,15 @@ public static class KeyValuePairSerializer
5161
/// <param name="keySerializer">The key serializer.</param>
5262
/// <param name="valueSerializer">The value Serializer.</param>
5363
/// <returns>A KeyValuePairSerializer.</returns>
54-
public static IBsonSerializer Create(
64+
public static IKeyValuePairSerializer Create(
5565
BsonType representation,
5666
IBsonSerializer keySerializer,
5767
IBsonSerializer valueSerializer)
5868
{
5969
var keyType = keySerializer.ValueType;
6070
var valueType = valueSerializer.ValueType;
6171
var keyValuePairSerializerType = typeof(KeyValuePairSerializer<,>).MakeGenericType(keyType, valueType);
62-
return (IBsonSerializer)Activator.CreateInstance(keyValuePairSerializerType, [representation, keySerializer, valueSerializer]);
72+
return (IKeyValuePairSerializer)Activator.CreateInstance(keyValuePairSerializerType, [representation, keySerializer, valueSerializer]);
6373
}
6474
}
6575

@@ -162,12 +172,15 @@ private KeyValuePairSerializer(BsonType representation, Lazy<IBsonSerializer<TKe
162172

163173
_helper = new SerializerHelper
164174
(
165-
new SerializerHelper.Member("k", Flags.Key),
166-
new SerializerHelper.Member("v", Flags.Value)
175+
new SerializerHelper.Member(KeyElementName, Flags.Key),
176+
new SerializerHelper.Member(ValueElementName, Flags.Value)
167177
);
168178
}
169179

170180
// public properties
181+
/// <inheritdoc/>
182+
public string KeyElementName => "k"; // might be configurable some day
183+
171184
/// <summary>
172185
/// Gets the key serializer.
173186
/// </summary>
@@ -181,17 +194,15 @@ public IBsonSerializer<TKey> KeySerializer
181194

182195
IBsonSerializer IKeyValuePairSerializer.KeySerializer => KeySerializer;
183196

184-
/// <summary>
185-
/// Gets the representation.
186-
/// </summary>
187-
/// <value>
188-
/// The representation.
189-
/// </value>
197+
/// <inheritdoc/>
190198
public BsonType Representation
191199
{
192200
get { return _representation; }
193201
}
194202

203+
/// <inheritdoc/>
204+
public string ValueElementName => "v"; // might be configurable some day
205+
195206
/// <summary>
196207
/// Gets the value serializer.
197208
/// </summary>
@@ -282,10 +293,10 @@ public bool TryGetMemberSerializationInfo(string memberName, out BsonSerializati
282293
switch (memberName)
283294
{
284295
case "Key":
285-
serializationInfo = new BsonSerializationInfo("k", _lazyKeySerializer.Value, _lazyKeySerializer.Value.ValueType);
296+
serializationInfo = new BsonSerializationInfo(KeyElementName, _lazyKeySerializer.Value, _lazyKeySerializer.Value.ValueType);
286297
return true;
287298
case "Value":
288-
serializationInfo = new BsonSerializationInfo("v", _lazyValueSerializer.Value, _lazyValueSerializer.Value.ValueType);
299+
serializationInfo = new BsonSerializationInfo(ValueElementName, _lazyValueSerializer.Value, _lazyValueSerializer.Value.ValueType);
289300
return true;
290301
}
291302

@@ -332,9 +343,9 @@ private void SerializeDocumentRepresentation(BsonSerializationContext context, K
332343
{
333344
var bsonWriter = context.Writer;
334345
bsonWriter.WriteStartDocument();
335-
bsonWriter.WriteName("k");
346+
bsonWriter.WriteName(KeyElementName);
336347
_lazyKeySerializer.Value.Serialize(context, value.Key);
337-
bsonWriter.WriteName("v");
348+
bsonWriter.WriteName(ValueElementName);
338349
_lazyValueSerializer.Value.Serialize(context, value.Value);
339350
bsonWriter.WriteEndDocument();
340351
}

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

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -736,10 +736,10 @@ protected override Expression VisitMethodCall(MethodCallExpression node)
736736
var arguments = node.Arguments;
737737

738738
DeduceMethodCallSerializers();
739-
if (IsKnown(node, out var knownSerializer) && knownSerializer is IUnknowableSerializer)
740-
{
741-
return node; // don't visit node any further
742-
}
739+
// if (IsKnown(node, out var knownSerializer) && knownSerializer is IUnknowableSerializer)
740+
// {
741+
// return node; // don't visit node any further
742+
// }
743743
base.VisitMethodCall(node);
744744
DeduceMethodCallSerializers();
745745

@@ -780,6 +780,7 @@ void DeduceMethodCallSerializers()
780780
case "Contains": DeduceContainsMethodSerializers(); break;
781781
case "ContainsKey": DeduceContainsKeyMethodSerializers(); break;
782782
case "ContainsValue": DeduceContainsValueMethodSerializers(); break;
783+
case "Convert": DeduceConvertMethodSerializers(); break;
783784
case "Cos": DeduceCosMethodSerializers(); break;
784785
case "Cosh": DeduceCoshMethodSerializers(); break;
785786
case "Create": DeduceCreateMethodSerializers(); break;
@@ -808,6 +809,7 @@ void DeduceMethodCallSerializers()
808809
case "Range": DeduceRangeMethodSerializers(); break;
809810
case "Repeat": DeduceRepeatMethodSerializers(); break;
810811
case "Reverse": DeduceReverseMethodSerializers(); break;
812+
case "Round": DeduceRoundMethodSerializers(); break;
811813
case "Select": DeduceSelectMethodSerializers(); break;
812814
case "SelectMany": DeduceSelectManySerializers(); break;
813815
case "SequenceEqual": DeduceSequenceEqualMethodSerializers(); break;
@@ -1592,6 +1594,58 @@ bool IsContainsValueInstanceMethod(out Expression collectionExpression, out Expr
15921594
}
15931595
}
15941596

1597+
void DeduceConvertMethodSerializers()
1598+
{
1599+
if (method.Is(MqlMethod.Convert))
1600+
{
1601+
if (IsNotKnown(node))
1602+
{
1603+
var toType = method.GetGenericArguments()[1];
1604+
var resultSerializer = GetResultSerializer(node, toType);
1605+
AddKnownSerializer(node, resultSerializer);
1606+
}
1607+
}
1608+
else
1609+
{
1610+
DeduceUnknownMethodSerializer();
1611+
}
1612+
1613+
static IBsonSerializer GetResultSerializer(Expression expression, Type toType)
1614+
{
1615+
var isNullable = toType.IsNullable();
1616+
var valueType = isNullable ? Nullable.GetUnderlyingType(toType) : toType;
1617+
1618+
var valueSerializer = (IBsonSerializer)(Type.GetTypeCode(valueType) switch
1619+
{
1620+
TypeCode.Boolean => BooleanSerializer.Instance,
1621+
TypeCode.Byte => ByteSerializer.Instance,
1622+
TypeCode.Char => StringSerializer.Instance,
1623+
TypeCode.DateTime => DateTimeSerializer.Instance,
1624+
TypeCode.Decimal => DecimalSerializer.Instance,
1625+
TypeCode.Double => DoubleSerializer.Instance,
1626+
TypeCode.Int16 => Int16Serializer.Instance,
1627+
TypeCode.Int32 => Int32Serializer.Instance,
1628+
TypeCode.Int64 => Int64Serializer.Instance,
1629+
TypeCode.SByte => SByteSerializer.Instance,
1630+
TypeCode.Single => SingleSerializer.Instance,
1631+
TypeCode.String => StringSerializer.Instance,
1632+
TypeCode.UInt16 => UInt16Serializer.Instance,
1633+
TypeCode.UInt32 => Int32Serializer.Instance,
1634+
TypeCode.UInt64 => UInt64Serializer.Instance,
1635+
1636+
_ when valueType == typeof(byte[]) => ByteArraySerializer.Instance,
1637+
_ when valueType == typeof(BsonBinaryData) => BsonBinaryDataSerializer.Instance,
1638+
_ when valueType == typeof(Decimal128) => Decimal128Serializer.Instance,
1639+
_ when valueType == typeof(Guid) => GuidSerializer.StandardInstance,
1640+
_ when valueType == typeof(ObjectId) => ObjectIdSerializer.Instance,
1641+
1642+
_ => throw new ExpressionNotSupportedException(expression, because: $"{toType} is not a valid TTo for Convert")
1643+
});
1644+
1645+
return isNullable ? NullableSerializer.Create(valueSerializer) : valueSerializer;
1646+
}
1647+
}
1648+
15951649
void DeduceCosMethodSerializers()
15961650
{
15971651
if (method.Is(MathMethod.Cos))
@@ -2795,6 +2849,22 @@ void DeduceReverseMethodSerializers()
27952849
}
27962850
}
27972851

2852+
void DeduceRoundMethodSerializers()
2853+
{
2854+
if (method.IsOneOf(MathMethod.RoundWithDecimal, MathMethod.RoundWithDecimalAndDecimals, MathMethod.RoundWithDouble, MathMethod.RoundWithDoubleAndDigits))
2855+
{
2856+
if (IsNotKnown(node))
2857+
{
2858+
var resultSerializer = StandardSerializers.GetSerializer(node.Type);
2859+
AddKnownSerializer(node, resultSerializer);
2860+
}
2861+
}
2862+
else
2863+
{
2864+
DeduceUnknownMethodSerializer();
2865+
}
2866+
}
2867+
27982868
void DeduceSelectMethodSerializers()
27992869
{
28002870
if (method.IsOneOf(EnumerableMethod.Select, QueryableMethod.Select))

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ static IBsonSerializer GetConvertEnumToEnumSerializer(UnaryExpression expression
204204
static IBsonSerializer GetConvertEnumToUnderlyingTypeSerializer(UnaryExpression expression, Type sourceType, Type targetType, IBsonSerializer sourceSerializer)
205205
{
206206
var enumSerializer = sourceSerializer;
207-
return ToEnumUnderlyingTypeSerializer.Create(enumSerializer);
207+
return AsEnumUnderlyingTypeSerializer.Create(enumSerializer);
208208
}
209209

210210
static IBsonSerializer GetConvertFromNullableTypeSerializer(UnaryExpression expression, Type sourceType, Type targetType, IBsonSerializer sourceSerializer)
@@ -246,7 +246,7 @@ static IBsonSerializer GetConvertToNullableTypeSerializer(UnaryExpression expres
246246
static IBsonSerializer GetConvertUnderlyingTypeToEnumSerializer(UnaryExpression expression, Type sourceType, Type targetType, IBsonSerializer sourceSerializer)
247247
{
248248
IBsonSerializer targetSerializer;
249-
if (sourceSerializer is IToEnumUnderlyingTypeSerializer enumUnderlyingTypeSerializer)
249+
if (sourceSerializer is IAsEnumUnderlyingTypeSerializer enumUnderlyingTypeSerializer)
250250
{
251251
targetSerializer = enumUnderlyingTypeSerializer.EnumSerializer;
252252
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public override Expression Visit(Expression node)
6969
{
7070
if (IsKnown(node, out var knownSerializer))
7171
{
72-
if (knownSerializer is IIgnoreSubtreeSerializer or IUnknowableSerializer)
72+
if (knownSerializer is IIgnoreSubtreeSerializer or IUnknowableSerializer) // TODO: call base.Visit for IUnknowableSerializer
7373
{
7474
return node; // don't visit subtree
7575
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,13 @@ public void AddSerializer(Expression node, IBsonSerializer serializer)
4040
{
4141
var enumType = nodeNonNullableType;
4242
var underlyingTypeSerializer = nullableSerializer.ValueSerializer;
43-
var enumSerializer = ToUnderlyingTypeEnumSerializer.Create(enumType, underlyingTypeSerializer);
43+
var enumSerializer = AsUnderlyingTypeEnumSerializer.Create(enumType, underlyingTypeSerializer);
4444
serializer = NullableSerializer.Create(enumSerializer);
4545
}
4646
else if (serializerNonNullableType.IsEnum(out var serializerUnderlyingType) && serializerUnderlyingType == nodeNonNullableType)
4747
{
4848
var enumSerializer = nullableSerializer.ValueSerializer;
49-
var underlyingTypeSerializer = ToEnumUnderlyingTypeSerializer.Create(enumSerializer);
49+
var underlyingTypeSerializer = AsEnumUnderlyingTypeSerializer.Create(enumSerializer);
5050
serializer = NullableSerializer.Create(underlyingTypeSerializer);
5151
}
5252
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,14 @@ public static bool IsKeyValuePairSerializer(
9292
{
9393
if (serializer is IKeyValuePairSerializer keyValuePairSerializer)
9494
{
95-
keyElementName = "k";
96-
valueElementName = "v";
95+
keyElementName = keyValuePairSerializer.KeyElementName;
96+
valueElementName = keyValuePairSerializer.ValueElementName;
9797
keySerializer = keyValuePairSerializer.KeySerializer;
9898
valueSerializer = keyValuePairSerializer.ValueSerializer;
9999
return true;
100100
}
101101

102-
// for backward compatibility not all KeyValuePair serializers implement IKeyValuePairSerializer
102+
// support user written custom KeyValuePair serializers that might not implement IKeyValuePairSerializer
103103
if (serializer.ValueType is var valueType &&
104104
valueType.IsConstructedGenericType &&
105105
valueType.GetGenericTypeDefinition() == typeof(KeyValuePair<,>) &&

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public static BsonType GetRepresentation(IBsonSerializer serializer)
9797
return GetRepresentation(downcastingSerializer.DerivedSerializer);
9898
}
9999

100-
if (serializer is IToEnumUnderlyingTypeSerializer enumUnderlyingTypeSerializer)
100+
if (serializer is IAsEnumUnderlyingTypeSerializer enumUnderlyingTypeSerializer)
101101
{
102102
return GetRepresentation(enumUnderlyingTypeSerializer.EnumSerializer);
103103
}

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ public static bool IsBoolean(this Type type)
226226

227227
public static bool IsBooleanOrNullableBoolean(this Type type)
228228
{
229-
return type.IsNullable(out var valueType) ? IsBoolean(valueType) : IsBoolean(type);
229+
return type == typeof(bool) || type.IsNullable(out var valueType) && IsBoolean(valueType);
230230
}
231231

232232
public static bool IsEnum(this Type type, out Type underlyingType)
@@ -321,7 +321,7 @@ TypeCode.UInt32 or
321321

322322
public static bool IsNumericOrNullableNumeric(this Type type)
323323
{
324-
return type.IsNullable(out var valueType) ? IsNumeric(valueType) : IsNumeric(type);
324+
return IsNumeric(type) || type.IsNullable(out var valueType) && IsNumeric(valueType);
325325
}
326326

327327
public static bool IsSameAsOrNullableOf(this Type type, Type valueType)
@@ -411,15 +411,15 @@ public static bool TryGetIListGenericInterface(this Type type, out Type ilistGen
411411

412412
public static bool TryGetIOrderedEnumerableGenericInterface(this Type type, out Type iOrderedEnumerableGenericInterface)
413413
{
414-
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IOrderedEnumerable<>))
414+
if (type.IsConstructedGenericType && type.GetGenericTypeDefinition() == typeof(IOrderedEnumerable<>))
415415
{
416416
iOrderedEnumerableGenericInterface = type;
417417
return true;
418418
}
419419

420420
foreach (var interfaceType in type.GetInterfaces())
421421
{
422-
if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IOrderedEnumerable<>))
422+
if (interfaceType.IsConstructedGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IOrderedEnumerable<>))
423423
{
424424
iOrderedEnumerableGenericInterface = interfaceType;
425425
return true;
@@ -432,15 +432,15 @@ public static bool TryGetIOrderedEnumerableGenericInterface(this Type type, out
432432

433433
public static bool TryGetIOrderedQueryableGenericInterface(this Type type, out Type iorderedQueryableGenericInterface)
434434
{
435-
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IOrderedQueryable<>))
435+
if (type.IsConstructedGenericType && type.GetGenericTypeDefinition() == typeof(IOrderedQueryable<>))
436436
{
437437
iorderedQueryableGenericInterface = type;
438438
return true;
439439
}
440440

441441
foreach (var interfaceType in type.GetInterfaces())
442442
{
443-
if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IOrderedQueryable<>))
443+
if (interfaceType.IsConstructedGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IOrderedQueryable<>))
444444
{
445445
iorderedQueryableGenericInterface = interfaceType;
446446
return true;
@@ -453,15 +453,15 @@ public static bool TryGetIOrderedQueryableGenericInterface(this Type type, out T
453453

454454
public static bool TryGetIQueryableGenericInterface(this Type type, out Type iqueryableGenericInterface)
455455
{
456-
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IQueryable<>))
456+
if (type.IsConstructedGenericType && type.GetGenericTypeDefinition() == typeof(IQueryable<>))
457457
{
458458
iqueryableGenericInterface = type;
459459
return true;
460460
}
461461

462462
foreach (var interfaceType in type.GetInterfaces())
463463
{
464-
if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IQueryable<>))
464+
if (interfaceType.IsConstructedGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IQueryable<>))
465465
{
466466
iqueryableGenericInterface = interfaceType;
467467
return true;

0 commit comments

Comments
 (0)