@@ -37,6 +37,205 @@ public static TNode SimplifyAndConvert<TNode>(TNode node)
37
37
}
38
38
#endregion
39
39
40
+ public override AstNode VisitFieldOperationFilter ( AstFieldOperationFilter node )
41
+ {
42
+ node = ( AstFieldOperationFilter ) base . VisitFieldOperationFilter ( node ) ;
43
+
44
+ if ( node . Field . Path != "@<elem>" )
45
+ {
46
+ // { field : { $eq : value } } => { field : value } where value is not a regex
47
+ if ( IsFieldEqValue ( node , out var value ) )
48
+ {
49
+ var impliedOperation = new AstImpliedOperationFilterOperation ( value ) ;
50
+ return new AstFieldOperationFilter ( node . Field , impliedOperation ) ;
51
+ }
52
+
53
+ // { field : { $regex : "pattern", $options : "options" } } => { field : /pattern/options }
54
+ if ( IsFieldRegex ( node , out var regex ) )
55
+ {
56
+ var impliedOperation = new AstImpliedOperationFilterOperation ( regex ) ;
57
+ return new AstFieldOperationFilter ( node . Field , impliedOperation ) ;
58
+ }
59
+
60
+ // { field : { $not : { $regex : "pattern", $options : "options" } } } => { field : { $not : /pattern/options } }
61
+ if ( IsFieldNotRegex ( node , out regex ) )
62
+ {
63
+ var notImpliedOperation = new AstNotFilterOperation ( new AstImpliedOperationFilterOperation ( regex ) ) ;
64
+ return new AstFieldOperationFilter ( node . Field , notImpliedOperation ) ;
65
+ }
66
+
67
+ // { field : { $elemMatch : { $eq : value } } } => { field : value } where value is not regex
68
+ if ( IsFieldElemMatchEqValue ( node , out value ) )
69
+ {
70
+ var impliedOperation = new AstImpliedOperationFilterOperation ( value ) ;
71
+ return new AstFieldOperationFilter ( node . Field , impliedOperation ) ;
72
+ }
73
+
74
+ // { field : { $elemMatch : { $regex : "pattern", $options : "options" } } } => { field : /pattern/options }
75
+ if ( IsFieldElemMatchRegex ( node , out regex ) )
76
+ {
77
+ var impliedOperation = new AstImpliedOperationFilterOperation ( regex ) ;
78
+ return new AstFieldOperationFilter ( node . Field , impliedOperation ) ;
79
+ }
80
+
81
+ // { field : { $elemMatch : { $not : { $regex : "pattern", $options : "options" } } } } => { field : { $elemMatch : { $not : /pattern/options } } }
82
+ if ( IsFieldElemMatchNotRegex ( node , out var elemField , out regex ) )
83
+ {
84
+ var notRegexOperation = new AstNotFilterOperation ( new AstImpliedOperationFilterOperation ( regex ) ) ;
85
+ var elemFilter = new AstFieldOperationFilter ( elemField , notRegexOperation ) ;
86
+ var elemMatchOperation = new AstElemMatchFilterOperation ( elemFilter ) ;
87
+ return new AstFieldOperationFilter ( node . Field , elemMatchOperation ) ;
88
+ }
89
+
90
+ // { field : { $not : { $elemMatch : { $eq : value } } } } => { field : { $ne : value } } where value is not regex
91
+ if ( IsFieldNotElemMatchEqValue ( node , out value ) )
92
+ {
93
+ var impliedOperation = new AstComparisonFilterOperation ( AstComparisonFilterOperator . Ne , value ) ;
94
+ return new AstFieldOperationFilter ( node . Field , impliedOperation ) ;
95
+ }
96
+
97
+ // { field : { $not : { $elemMatch : { $regex : "pattern", $options : "options" } } } } => { field : { $not : /pattern/options } }
98
+ if ( IsFieldNotElemMatchRegex ( node , out regex ) )
99
+ {
100
+ var notImpliedOperation = new AstNotFilterOperation ( new AstImpliedOperationFilterOperation ( regex ) ) ;
101
+ return new AstFieldOperationFilter ( node . Field , notImpliedOperation ) ;
102
+ }
103
+ }
104
+
105
+ return node ;
106
+
107
+ static bool IsFieldEqValue ( AstFieldOperationFilter node , out BsonValue value )
108
+ {
109
+ // { field : { $eq : value } } where value is not a a regex
110
+ if ( node . Operation is AstComparisonFilterOperation comparisonOperation &&
111
+ comparisonOperation . Operator == AstComparisonFilterOperator . Eq &&
112
+ comparisonOperation . Value . BsonType != BsonType . RegularExpression )
113
+ {
114
+ value = comparisonOperation . Value ;
115
+ return true ;
116
+ }
117
+
118
+ value = null ;
119
+ return false ;
120
+ }
121
+
122
+ static bool IsFieldRegex ( AstFieldOperationFilter node , out BsonRegularExpression regex )
123
+ {
124
+ // { field : { $regex : "pattern", $options : "options" } }
125
+ if ( node . Operation is AstRegexFilterOperation regexOperation )
126
+ {
127
+ regex = new BsonRegularExpression ( regexOperation . Pattern , regexOperation . Options ) ;
128
+ return true ;
129
+ }
130
+
131
+ regex = null ;
132
+ return false ;
133
+ }
134
+
135
+ static bool IsFieldNotRegex ( AstFieldOperationFilter node , out BsonRegularExpression regex )
136
+ {
137
+ // { field : { $not : { $regex : "pattern", $options : "options" } } }
138
+ if ( node . Operation is AstNotFilterOperation notOperation &&
139
+ notOperation . Operation is AstRegexFilterOperation regexOperation )
140
+ {
141
+ regex = new BsonRegularExpression ( regexOperation . Pattern , regexOperation . Options ) ;
142
+ return true ;
143
+ }
144
+
145
+ regex = null ;
146
+ return false ;
147
+ }
148
+
149
+ static bool IsFieldElemMatchEqValue ( AstFieldOperationFilter node , out BsonValue value )
150
+ {
151
+ // { field : { $elemMatch : { $eq : value } } } where value is not regex
152
+ if ( node . Operation is AstElemMatchFilterOperation elemMatchOperation &&
153
+ elemMatchOperation . Filter is AstFieldOperationFilter elemFilter &&
154
+ elemFilter . Field . Path == "@<elem>" &&
155
+ elemFilter . Operation is AstComparisonFilterOperation comparisonOperation &&
156
+ comparisonOperation . Operator == AstComparisonFilterOperator . Eq &&
157
+ comparisonOperation . Value . BsonType != BsonType . RegularExpression )
158
+ {
159
+ value = comparisonOperation . Value ;
160
+ return true ;
161
+ }
162
+
163
+ value = null ;
164
+ return false ;
165
+ }
166
+
167
+ static bool IsFieldElemMatchRegex ( AstFieldOperationFilter node , out BsonRegularExpression regex )
168
+ {
169
+ // { field : { $elemMatch : { $regex : "pattern", $options : "options" } } }
170
+ if ( node . Operation is AstElemMatchFilterOperation elemMatchOperation &&
171
+ elemMatchOperation . Filter is AstFieldOperationFilter elemFilter &&
172
+ elemFilter . Field . Path == "@<elem>" &&
173
+ elemFilter . Operation is AstRegexFilterOperation regexOperation )
174
+ {
175
+ regex = new BsonRegularExpression ( regexOperation . Pattern , regexOperation . Options ) ;
176
+ return true ;
177
+ }
178
+
179
+ regex = null ;
180
+ return false ;
181
+ }
182
+
183
+ static bool IsFieldElemMatchNotRegex ( AstFieldOperationFilter node , out AstFilterField elemField , out BsonRegularExpression regex )
184
+ {
185
+ // { field : { $elemMatch : { $not : { $regex : "pattern", $options : "options" } } } }
186
+ if ( node . Operation is AstElemMatchFilterOperation elemMatch &&
187
+ elemMatch . Filter is AstFieldOperationFilter elemFilter &&
188
+ elemFilter . Field . Path == "@<elem>" &&
189
+ elemFilter . Operation is AstNotFilterOperation notOperation &&
190
+ notOperation . Operation is AstRegexFilterOperation regexOperation )
191
+ {
192
+ elemField = elemFilter . Field ;
193
+ regex = new BsonRegularExpression ( regexOperation . Pattern , regexOperation . Options ) ;
194
+ return true ;
195
+ }
196
+
197
+ elemField = null ;
198
+ regex = null ;
199
+ return false ;
200
+ }
201
+
202
+ static bool IsFieldNotElemMatchEqValue ( AstFieldOperationFilter node , out BsonValue value )
203
+ {
204
+ // { field : { $not : { $elemMatch : { $eq : value } } } } where value is not regex
205
+ if ( node . Operation is AstNotFilterOperation notFilterOperation &&
206
+ notFilterOperation . Operation is AstElemMatchFilterOperation elemMatchOperation &&
207
+ elemMatchOperation . Filter is AstFieldOperationFilter elemFilter &&
208
+ elemFilter . Field . Path == "@<elem>" &&
209
+ elemFilter . Operation is AstComparisonFilterOperation comparisonOperation &&
210
+ comparisonOperation . Operator == AstComparisonFilterOperator . Eq &&
211
+ comparisonOperation . Value . BsonType != BsonType . RegularExpression )
212
+ {
213
+ value = comparisonOperation . Value ;
214
+ return true ;
215
+ }
216
+
217
+ value = null ;
218
+ return false ;
219
+ }
220
+
221
+ static bool IsFieldNotElemMatchRegex ( AstFieldOperationFilter node , out BsonRegularExpression regex )
222
+ {
223
+ // { field : { $not : { $elemMatch : { $regex : "pattern", $options : "options" } } } }
224
+ if ( node . Operation is AstNotFilterOperation notFilterOperation &&
225
+ notFilterOperation . Operation is AstElemMatchFilterOperation elemMatchOperation &&
226
+ elemMatchOperation . Filter is AstFieldOperationFilter elemFilter &&
227
+ elemFilter . Field . Path == "@<elem>" &&
228
+ elemFilter . Operation is AstRegexFilterOperation regexOperation )
229
+ {
230
+ regex = new BsonRegularExpression ( regexOperation . Pattern , regexOperation . Options ) ;
231
+ return true ;
232
+ }
233
+
234
+ regex = null ;
235
+ return false ;
236
+ }
237
+ }
238
+
40
239
public override AstNode VisitGetFieldExpression ( AstGetFieldExpression node )
41
240
{
42
241
if ( TrySimplifyAsFieldPath ( node , out var simplified ) )
0 commit comments