@@ -28,115 +28,61 @@ internal static class ConvertExpressionToFilterFieldTranslator
28
28
{
29
29
public static AstFilterField Translate ( TranslationContext context , UnaryExpression expression )
30
30
{
31
- if ( expression . NodeType == ExpressionType . Convert )
31
+ if ( expression . NodeType == ExpressionType . Convert || expression . NodeType == ExpressionType . TypeAs )
32
32
{
33
33
var field = ExpressionToFilterFieldTranslator . Translate ( context , expression . Operand ) ;
34
- var fieldSerializer = field . Serializer ;
35
- var fieldType = fieldSerializer . ValueType ;
34
+ var fieldType = field . Serializer . ValueType ;
36
35
var targetType = expression . Type ;
37
36
38
- if ( fieldType . IsEnumOrNullableEnum ( out _ , out var underlyingType ) )
37
+ if ( IsConvertEnumToUnderlyingType ( fieldType , targetType ) )
39
38
{
40
- if ( targetType . IsSameAsOrNullableOf ( underlyingType ) )
41
- {
42
- IBsonSerializer enumSerializer ;
43
- if ( fieldType . IsNullable ( ) )
44
- {
45
- var nullableSerializer = ( INullableSerializer ) fieldSerializer ;
46
- enumSerializer = nullableSerializer . ValueSerializer ;
47
- }
48
- else
49
- {
50
- enumSerializer = fieldSerializer ;
51
- }
52
-
53
- IBsonSerializer targetSerializer ;
54
- var enumUnderlyingTypeSerializer = EnumUnderlyingTypeSerializer . Create ( enumSerializer ) ;
55
- if ( targetType . IsNullable ( ) )
56
- {
57
- targetSerializer = NullableSerializer . Create ( enumUnderlyingTypeSerializer ) ;
58
- }
59
- else
60
- {
61
- targetSerializer = enumUnderlyingTypeSerializer ;
62
- }
63
-
64
- return AstFilter . Field ( field . Path , targetSerializer ) ;
65
- }
39
+ return TranslateConvertEnumToUnderlyingType ( field , targetType ) ;
66
40
}
67
41
68
- if ( IsNumericType ( targetType ) )
42
+ if ( IsNumericConversion ( fieldType , targetType ) )
69
43
{
70
- IBsonSerializer targetTypeSerializer = expression . Type switch
71
- {
72
- Type t when t == typeof ( byte ) => new ByteSerializer ( ) ,
73
- Type t when t == typeof ( short ) => new Int16Serializer ( ) ,
74
- Type t when t == typeof ( ushort ) => new UInt16Serializer ( ) ,
75
- Type t when t == typeof ( int ) => new Int32Serializer ( ) ,
76
- Type t when t == typeof ( uint ) => new UInt32Serializer ( ) ,
77
- Type t when t == typeof ( long ) => new Int64Serializer ( ) ,
78
- Type t when t == typeof ( ulong ) => new UInt64Serializer ( ) ,
79
- Type t when t == typeof ( float ) => new SingleSerializer ( ) ,
80
- Type t when t == typeof ( double ) => new DoubleSerializer ( ) ,
81
- Type t when t == typeof ( decimal ) => new DecimalSerializer ( ) ,
82
- _ => throw new ExpressionNotSupportedException ( expression )
83
- } ;
84
- if ( fieldSerializer is IRepresentationConfigurable representationConfigurableFieldSerializer &&
85
- targetTypeSerializer is IRepresentationConfigurable representationConfigurableTargetTypeSerializer )
86
- {
87
- var fieldRepresentation = representationConfigurableFieldSerializer . Representation ;
88
- if ( fieldRepresentation == BsonType . String )
89
- {
90
- targetTypeSerializer = representationConfigurableTargetTypeSerializer . WithRepresentation ( fieldRepresentation ) ;
91
- }
92
- }
93
- if ( fieldSerializer is IRepresentationConverterConfigurable converterConfigurableFieldSerializer &&
94
- targetTypeSerializer is IRepresentationConverterConfigurable converterConfigurableTargetTypeSerializer )
95
- {
96
- targetTypeSerializer = converterConfigurableTargetTypeSerializer . WithConverter ( converterConfigurableFieldSerializer . Converter ) ;
97
- }
98
- return AstFilter . Field ( field . Path , targetTypeSerializer ) ;
44
+ return TranslateNumericConversion ( field , targetType ) ;
99
45
}
100
46
101
- if ( targetType . IsConstructedGenericType &&
102
- targetType . GetGenericTypeDefinition ( ) == typeof ( Nullable < > ) )
47
+ if ( IsConvertToNullable ( fieldType , targetType ) )
103
48
{
104
- var nullableValueType = targetType . GetGenericArguments ( ) [ 0 ] ;
105
- if ( nullableValueType == fieldType )
106
- {
107
- var nullableSerializerType = typeof ( NullableSerializer < > ) . MakeGenericType ( nullableValueType ) ;
108
- var nullableSerializer = ( IBsonSerializer ) Activator . CreateInstance ( nullableSerializerType , fieldSerializer ) ;
109
- return AstFilter . Field ( field . Path , nullableSerializer ) ;
110
- }
111
-
112
- if ( fieldType . IsConstructedGenericType &&
113
- fieldType . GetGenericTypeDefinition ( ) == typeof ( Nullable < > ) )
114
- {
115
- var fieldValueType = fieldType . GetGenericArguments ( ) [ 0 ] ;
116
- if ( fieldValueType . IsEnum )
117
- {
118
- var enumUnderlyingType = fieldValueType . GetEnumUnderlyingType ( ) ;
119
- if ( nullableValueType == enumUnderlyingType )
120
- {
121
- var fieldSerializerType = fieldSerializer . GetType ( ) ;
122
- if ( fieldSerializerType . IsConstructedGenericType &&
123
- fieldSerializerType . GetGenericTypeDefinition ( ) == typeof ( NullableSerializer < > ) )
124
- {
125
- var enumSerializer = ( ( IChildSerializerConfigurable ) fieldSerializer ) . ChildSerializer ;
126
- var enumUnderlyingTypeSerializer = EnumUnderlyingTypeSerializer . Create ( enumSerializer ) ;
127
- var nullableSerializerType = typeof ( NullableSerializer < > ) . MakeGenericType ( nullableValueType ) ;
128
- var nullableSerializer = ( IBsonSerializer ) Activator . CreateInstance ( nullableSerializerType , enumUnderlyingTypeSerializer ) ;
129
- return AstFilter . Field ( field . Path , nullableSerializer ) ;
130
- }
131
- }
132
- }
133
- }
49
+ return TranslateConvertToNullable ( field ) ;
50
+ }
51
+
52
+ if ( IsConvertToDerivedType ( fieldType , targetType ) )
53
+ {
54
+ return TranslateConvertToDerivedType ( field , targetType ) ;
134
55
}
135
56
}
136
57
137
58
throw new ExpressionNotSupportedException ( expression ) ;
138
59
}
139
60
61
+ private static bool IsConvertEnumToUnderlyingType ( Type fieldType , Type targetType )
62
+ {
63
+ return
64
+ fieldType . IsEnumOrNullableEnum ( out _ , out var underlyingType ) &&
65
+ targetType . IsSameAsOrNullableOf ( underlyingType ) ;
66
+ }
67
+
68
+ private static bool IsConvertToDerivedType ( Type fieldType , Type targetType )
69
+ {
70
+ return targetType . IsSubclassOf ( fieldType ) ;
71
+ }
72
+
73
+ private static bool IsConvertToNullable ( Type fieldType , Type targetType )
74
+ {
75
+ return
76
+ targetType . IsConstructedGenericType &&
77
+ targetType . GetGenericTypeDefinition ( ) == typeof ( Nullable < > ) &&
78
+ targetType . GetGenericArguments ( ) [ 0 ] == fieldType ;
79
+ }
80
+
81
+ private static bool IsNumericConversion ( Type fieldType , Type targetType )
82
+ {
83
+ return IsNumericType ( fieldType ) && IsNumericType ( targetType ) ;
84
+ }
85
+
140
86
private static bool IsNumericType ( Type type )
141
87
{
142
88
switch ( Type . GetTypeCode ( type ) )
@@ -147,6 +93,7 @@ private static bool IsNumericType(Type type)
147
93
case TypeCode . Int16 :
148
94
case TypeCode . Int32 :
149
95
case TypeCode . Int64 :
96
+ case TypeCode . SByte :
150
97
case TypeCode . Single :
151
98
case TypeCode . UInt16 :
152
99
case TypeCode . UInt32 :
@@ -157,5 +104,81 @@ private static bool IsNumericType(Type type)
157
104
return false ;
158
105
}
159
106
}
107
+
108
+ private static AstFilterField TranslateConvertEnumToUnderlyingType ( AstFilterField field , Type targetType )
109
+ {
110
+ var fieldSerializer = field . Serializer ;
111
+ var fieldType = fieldSerializer . ValueType ;
112
+
113
+ IBsonSerializer enumSerializer ;
114
+ if ( fieldType . IsNullable ( ) )
115
+ {
116
+ var nullableSerializer = ( INullableSerializer ) fieldSerializer ;
117
+ enumSerializer = nullableSerializer . ValueSerializer ;
118
+ }
119
+ else
120
+ {
121
+ enumSerializer = fieldSerializer ;
122
+ }
123
+
124
+ IBsonSerializer targetSerializer ;
125
+ var enumUnderlyingTypeSerializer = EnumUnderlyingTypeSerializer . Create ( enumSerializer ) ;
126
+ if ( targetType . IsNullable ( ) )
127
+ {
128
+ targetSerializer = NullableSerializer . Create ( enumUnderlyingTypeSerializer ) ;
129
+ }
130
+ else
131
+ {
132
+ targetSerializer = enumUnderlyingTypeSerializer ;
133
+ }
134
+
135
+ return AstFilter . Field ( field . Path , targetSerializer ) ;
136
+ }
137
+
138
+ private static AstFilterField TranslateConvertToDerivedType ( AstFilterField field , Type targetType )
139
+ {
140
+ var targetSerializer = BsonSerializer . LookupSerializer ( targetType ) ;
141
+ return AstFilter . Field ( field . Path , targetSerializer ) ;
142
+ }
143
+
144
+ private static AstFilterField TranslateConvertToNullable ( AstFilterField field )
145
+ {
146
+ var nullableSerializer = NullableSerializer . Create ( field . Serializer ) ;
147
+ return AstFilter . Field ( field . Path , nullableSerializer ) ;
148
+ }
149
+
150
+ private static AstFilterField TranslateNumericConversion ( AstFilterField field , Type targetType )
151
+ {
152
+ IBsonSerializer targetTypeSerializer = targetType switch
153
+ {
154
+ Type t when t == typeof ( byte ) => new ByteSerializer ( ) ,
155
+ Type t when t == typeof ( sbyte ) => new SByteSerializer ( ) ,
156
+ Type t when t == typeof ( short ) => new Int16Serializer ( ) ,
157
+ Type t when t == typeof ( ushort ) => new UInt16Serializer ( ) ,
158
+ Type t when t == typeof ( int ) => new Int32Serializer ( ) ,
159
+ Type t when t == typeof ( uint ) => new UInt32Serializer ( ) ,
160
+ Type t when t == typeof ( long ) => new Int64Serializer ( ) ,
161
+ Type t when t == typeof ( ulong ) => new UInt64Serializer ( ) ,
162
+ Type t when t == typeof ( float ) => new SingleSerializer ( ) ,
163
+ Type t when t == typeof ( double ) => new DoubleSerializer ( ) ,
164
+ Type t when t == typeof ( decimal ) => new DecimalSerializer ( ) ,
165
+ _ => throw new Exception ( $ "Unexpected target type: { targetType } .")
166
+ } ;
167
+ if ( field . Serializer is IRepresentationConfigurable representationConfigurableFieldSerializer &&
168
+ targetTypeSerializer is IRepresentationConfigurable representationConfigurableTargetTypeSerializer )
169
+ {
170
+ var fieldRepresentation = representationConfigurableFieldSerializer . Representation ;
171
+ if ( fieldRepresentation == BsonType . String )
172
+ {
173
+ targetTypeSerializer = representationConfigurableTargetTypeSerializer . WithRepresentation ( fieldRepresentation ) ;
174
+ }
175
+ }
176
+ if ( field . Serializer is IRepresentationConverterConfigurable converterConfigurableFieldSerializer &&
177
+ targetTypeSerializer is IRepresentationConverterConfigurable converterConfigurableTargetTypeSerializer )
178
+ {
179
+ targetTypeSerializer = converterConfigurableTargetTypeSerializer . WithConverter ( converterConfigurableFieldSerializer . Converter ) ;
180
+ }
181
+ return AstFilter . Field ( field . Path , targetTypeSerializer ) ;
182
+ }
160
183
}
161
184
}
0 commit comments