14
14
*/
15
15
16
16
using System . Collections . Generic ;
17
+ using System . Collections . ObjectModel ;
17
18
using System . Linq ;
18
19
using System . Linq . Expressions ;
19
20
using System . Reflection ;
21
+ using MongoDB . Bson ;
22
+ using MongoDB . Bson . IO ;
20
23
using MongoDB . Bson . Serialization . Serializers ;
21
24
using MongoDB . Driver . Linq . Linq3Implementation . Ast . Expressions ;
22
25
using MongoDB . Driver . Linq . Linq3Implementation . Misc ;
@@ -27,20 +30,48 @@ internal static class StringConcatMethodToAggregationExpressionTranslator
27
30
{
28
31
private static readonly MethodInfo [ ] __stringConcatMethods = new [ ]
29
32
{
33
+ StringMethod . ConcatWith1Object ,
34
+ StringMethod . ConcatWith2Objects ,
35
+ StringMethod . ConcatWith3Objects ,
36
+ StringMethod . ConcatWithObjectArray ,
30
37
StringMethod . ConcatWith2Strings ,
31
38
StringMethod . ConcatWith3Strings ,
32
39
StringMethod . ConcatWith4Strings ,
33
40
StringMethod . ConcatWithStringArray
34
41
} ;
35
42
36
- public static bool CanTranslate ( MethodCallExpression expression )
37
- => expression . Method . IsOneOf ( __stringConcatMethods ) ;
43
+ public static bool CanTranslate ( BinaryExpression expression , out MethodInfo method , out ReadOnlyCollection < Expression > arguments )
44
+ {
45
+ if ( expression . NodeType == ExpressionType . Add &&
46
+ expression . Method != null &&
47
+ expression . Method . IsOneOf ( StringMethod . ConcatWith2Objects , StringMethod . ConcatWith2Strings ) )
48
+ {
49
+ method = expression . Method ;
50
+ arguments = new ReadOnlyCollection < Expression > ( new [ ] { expression . Left , expression . Right } ) ;
51
+ return true ;
52
+ }
53
+
54
+ method = null ;
55
+ arguments = null ;
56
+ return false ;
57
+ }
38
58
39
- public static AggregationExpression Translate ( TranslationContext context , MethodCallExpression expression )
59
+ public static bool CanTranslate ( MethodCallExpression expression , out MethodInfo method , out ReadOnlyCollection < Expression > arguments )
40
60
{
41
- var method = expression . Method ;
42
- var arguments = expression . Arguments ;
61
+ if ( expression . Method . IsOneOf ( __stringConcatMethods ) )
62
+ {
63
+ method = expression . Method ;
64
+ arguments = expression . Arguments ;
65
+ return true ;
66
+ }
43
67
68
+ method = null ;
69
+ arguments = null ;
70
+ return false ;
71
+ }
72
+
73
+ public static AggregationExpression Translate ( TranslationContext context , Expression expression , MethodInfo method , ReadOnlyCollection < Expression > arguments )
74
+ {
44
75
IEnumerable < AstExpression > argumentsTranslations = null ;
45
76
46
77
if ( method . IsOneOf (
@@ -52,6 +83,16 @@ public static AggregationExpression Translate(TranslationContext context, Method
52
83
arguments . Select ( a => ExpressionToAggregationExpressionTranslator . Translate ( context , a ) . Ast ) ;
53
84
}
54
85
86
+ if ( method . IsOneOf (
87
+ StringMethod . ConcatWith1Object ,
88
+ StringMethod . ConcatWith2Objects ,
89
+ StringMethod . ConcatWith3Objects ) )
90
+ {
91
+ argumentsTranslations = arguments
92
+ . Select ( a => ExpressionToAggregationExpressionTranslator . Translate ( context , a ) )
93
+ . Select ( ExpressionToString ) ;
94
+ }
95
+
55
96
if ( method . Is ( StringMethod . ConcatWithStringArray ) )
56
97
{
57
98
var argumentTranslation = ExpressionToAggregationExpressionTranslator . Translate ( context , arguments . Single ( ) ) ;
@@ -61,13 +102,61 @@ public static AggregationExpression Translate(TranslationContext context, Method
61
102
}
62
103
}
63
104
105
+ if ( method . Is ( StringMethod . ConcatWithObjectArray ) )
106
+ {
107
+ if ( arguments . Single ( ) is NewArrayExpression newArrayExpression )
108
+ {
109
+ argumentsTranslations = newArrayExpression . Expressions
110
+ . Select ( a => ExpressionToAggregationExpressionTranslator . Translate ( context , a ) )
111
+ . Select ( ExpressionToString ) ;
112
+ }
113
+ }
114
+
64
115
if ( argumentsTranslations != null )
65
116
{
66
117
var ast = AstExpression . Concat ( argumentsTranslations . ToArray ( ) ) ;
67
118
return new AggregationExpression ( expression , ast , StringSerializer . Instance ) ;
68
119
}
69
120
70
121
throw new ExpressionNotSupportedException ( expression ) ;
122
+
123
+ static AstExpression ExpressionToString ( AggregationExpression aggregationExpression )
124
+ {
125
+ var astExpression = aggregationExpression . Ast ;
126
+ if ( aggregationExpression . Serializer . ValueType == typeof ( string ) )
127
+ {
128
+ return astExpression ;
129
+ }
130
+ else
131
+ {
132
+ if ( astExpression is AstConstantExpression constantAstExpression )
133
+ {
134
+ var value = constantAstExpression . Value ;
135
+ var stringValue = ValueToString ( aggregationExpression . Expression , value ) ;
136
+ return AstExpression . Constant ( stringValue ) ;
137
+ }
138
+ else
139
+ {
140
+ return AstExpression . ToString ( astExpression ) ;
141
+ }
142
+ }
143
+ }
144
+
145
+ static string ValueToString ( Expression expression , BsonValue value )
146
+ {
147
+ return value switch
148
+ {
149
+ BsonBoolean booleanValue => JsonConvert . ToString ( booleanValue . Value ) ,
150
+ BsonDateTime dateTimeValue => JsonConvert . ToString ( dateTimeValue . ToUniversalTime ( ) ) ,
151
+ BsonDecimal128 decimalValue => JsonConvert . ToString ( decimalValue . Value ) ,
152
+ BsonDouble doubleValue => JsonConvert . ToString ( doubleValue . Value ) ,
153
+ BsonInt32 int32Value => JsonConvert . ToString ( int32Value . Value ) ,
154
+ BsonInt64 int64Value => JsonConvert . ToString ( int64Value . Value ) ,
155
+ BsonObjectId objectIdValue => objectIdValue . Value . ToString ( ) ,
156
+ BsonString stringValue => stringValue . Value ,
157
+ _ => throw new ExpressionNotSupportedException ( expression , because : $ "values represented as BSON type { value . BsonType } are not supported by $toString")
158
+ } ;
159
+ }
71
160
}
72
161
}
73
162
}
0 commit comments