1414*/
1515
1616using System . Collections . Generic ;
17+ using System . Collections . ObjectModel ;
1718using System . Linq ;
1819using System . Linq . Expressions ;
1920using System . Reflection ;
21+ using MongoDB . Bson ;
22+ using MongoDB . Bson . IO ;
2023using MongoDB . Bson . Serialization . Serializers ;
2124using MongoDB . Driver . Linq . Linq3Implementation . Ast . Expressions ;
2225using MongoDB . Driver . Linq . Linq3Implementation . Misc ;
@@ -27,20 +30,48 @@ internal static class StringConcatMethodToAggregationExpressionTranslator
2730 {
2831 private static readonly MethodInfo [ ] __stringConcatMethods = new [ ]
2932 {
33+ StringMethod . ConcatWith1Object ,
34+ StringMethod . ConcatWith2Objects ,
35+ StringMethod . ConcatWith3Objects ,
36+ StringMethod . ConcatWithObjectArray ,
3037 StringMethod . ConcatWith2Strings ,
3138 StringMethod . ConcatWith3Strings ,
3239 StringMethod . ConcatWith4Strings ,
3340 StringMethod . ConcatWithStringArray
3441 } ;
3542
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+ }
3858
39- public static AggregationExpression Translate ( TranslationContext context , MethodCallExpression expression )
59+ public static bool CanTranslate ( MethodCallExpression expression , out MethodInfo method , out ReadOnlyCollection < Expression > arguments )
4060 {
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+ }
4367
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+ {
4475 IEnumerable < AstExpression > argumentsTranslations = null ;
4576
4677 if ( method . IsOneOf (
@@ -52,6 +83,16 @@ public static AggregationExpression Translate(TranslationContext context, Method
5283 arguments . Select ( a => ExpressionToAggregationExpressionTranslator . Translate ( context , a ) . Ast ) ;
5384 }
5485
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+
5596 if ( method . Is ( StringMethod . ConcatWithStringArray ) )
5697 {
5798 var argumentTranslation = ExpressionToAggregationExpressionTranslator . Translate ( context , arguments . Single ( ) ) ;
@@ -61,13 +102,61 @@ public static AggregationExpression Translate(TranslationContext context, Method
61102 }
62103 }
63104
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+
64115 if ( argumentsTranslations != null )
65116 {
66117 var ast = AstExpression . Concat ( argumentsTranslations . ToArray ( ) ) ;
67118 return new AggregationExpression ( expression , ast , StringSerializer . Instance ) ;
68119 }
69120
70121 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+ }
71160 }
72161 }
73162}
0 commit comments