@@ -2208,6 +2208,152 @@ TEST(ExpressionPowTest, NegativeOneRaisedToNegativeOddExponentShouldOutPutNegati
2208
2208
});
2209
2209
}
2210
2210
2211
+ TEST (ExpressionArray, ExpressionArrayWithAllConstantValuesShouldOptimizeToExpressionConstant) {
2212
+ intrusive_ptr<ExpressionContextForTest> expCtx (new ExpressionContextForTest ());
2213
+ VariablesParseState vps = expCtx->variablesParseState ;
2214
+
2215
+ // ExpressionArray of constant values should optimize to ExpressionConsant.
2216
+ BSONObj bsonarrayOfConstants = BSON (" " << BSON_ARRAY (1 << 2 << 3 << 4 ));
2217
+ BSONElement elementArray = bsonarrayOfConstants.firstElement ();
2218
+ auto expressionArr = ExpressionArray::parse (expCtx, elementArray, vps);
2219
+ auto optimizedToConstant = expressionArr->optimize ();
2220
+ auto exprConstant = dynamic_cast <ExpressionConstant*>(optimizedToConstant.get ());
2221
+ ASSERT_TRUE (exprConstant);
2222
+
2223
+ // ExpressionArray with not all constant values should not optimize to ExpressionConstant.
2224
+ BSONObj bsonarray = BSON (" " << BSON_ARRAY (1 << " $x" << 3 << 4 ));
2225
+ BSONElement elementArrayNotConstant = bsonarray.firstElement ();
2226
+ auto expressionArrNotConstant = ExpressionArray::parse (expCtx, elementArrayNotConstant, vps);
2227
+ auto notOptimized = expressionArrNotConstant->optimize ();
2228
+ auto notExprConstant = dynamic_cast <ExpressionConstant*>(notOptimized.get ());
2229
+ ASSERT_FALSE (notExprConstant);
2230
+ }
2231
+
2232
+ TEST (ExpressionArray, ExpressionArrayShouldOptimizeSubExpressionToExpressionConstant) {
2233
+ intrusive_ptr<ExpressionContextForTest> expCtx (new ExpressionContextForTest ());
2234
+ VariablesParseState vps = expCtx->variablesParseState ;
2235
+
2236
+
2237
+ // ExpressionArray with constant values and sub expression that evaluates to constant should
2238
+ // optimize to Expression constant.
2239
+ BSONObj bsonarrayWithSubExpression =
2240
+ BSON (" " << BSON_ARRAY (1 << BSON (" $add" << BSON_ARRAY (1 << 1 )) << 3 << 4 ));
2241
+ BSONElement elementArrayWithSubExpression = bsonarrayWithSubExpression.firstElement ();
2242
+ auto expressionArrWithSubExpression =
2243
+ ExpressionArray::parse (expCtx, elementArrayWithSubExpression, vps);
2244
+ auto optimizedToConstantWithSubExpression = expressionArrWithSubExpression->optimize ();
2245
+ auto constantExpression =
2246
+ dynamic_cast <ExpressionConstant*>(optimizedToConstantWithSubExpression.get ());
2247
+ ASSERT_TRUE (constantExpression);
2248
+ }
2249
+
2250
+ TEST (ExpressionIndexOfArray, ExpressionIndexOfArrayShouldOptimizeArguments) {
2251
+ intrusive_ptr<ExpressionContextForTest> expCtx (new ExpressionContextForTest ());
2252
+
2253
+ auto expIndexOfArray = Expression::parseExpression (
2254
+ expCtx, // 2, 1, 1
2255
+ BSON (" $indexOfArray" << BSON_ARRAY (
2256
+ BSON_ARRAY (BSON (" $add" << BSON_ARRAY (1 << 1 )) << 1 << 1 << 2 )
2257
+ // Value we are searching for = 2.
2258
+ << BSON (" $add" << BSON_ARRAY (1 << 1 ))
2259
+ // Start index = 1.
2260
+ << BSON (" $add" << BSON_ARRAY (0 << 1 ))
2261
+ // End index = 4.
2262
+ << BSON (" $add" << BSON_ARRAY (1 << 3 )))),
2263
+ expCtx->variablesParseState );
2264
+ auto argsOptimizedToConstants = expIndexOfArray->optimize ();
2265
+ auto shouldBeIndexOfArray = dynamic_cast <ExpressionConstant*>(argsOptimizedToConstants.get ());
2266
+ ASSERT_TRUE (shouldBeIndexOfArray);
2267
+ ASSERT_VALUE_EQ (Value (3 ), shouldBeIndexOfArray->getValue ());
2268
+ }
2269
+
2270
+ TEST (ExpressionIndexOfArray,
2271
+ ExpressionIndexOfArrayShouldOptimizeNullishInputArrayToExpressionConstant) {
2272
+ intrusive_ptr<ExpressionContextForTest> expCtx (new ExpressionContextForTest ());
2273
+ VariablesParseState vps = expCtx->variablesParseState ;
2274
+
2275
+ auto expIndex = Expression::parseExpression (
2276
+ expCtx, fromjson (" { $indexOfArray : [ undefined , 1, 1]}" ), expCtx->variablesParseState );
2277
+
2278
+ auto isExpIndexOfArray = dynamic_cast <ExpressionIndexOfArray*>(expIndex.get ());
2279
+ ASSERT_TRUE (isExpIndexOfArray);
2280
+
2281
+ auto nullishValueOptimizedToExpConstant = isExpIndexOfArray->optimize ();
2282
+ auto shouldBeExpressionConstant =
2283
+ dynamic_cast <ExpressionConstant*>(nullishValueOptimizedToExpConstant.get ());
2284
+ ASSERT_TRUE (shouldBeExpressionConstant);
2285
+ // Nullish input array should become a Value(BSONNULL).
2286
+ ASSERT_VALUE_EQ (Value (BSONNULL), shouldBeExpressionConstant->getValue ());
2287
+ }
2288
+
2289
+ TEST (ExpressionIndexOfArray,
2290
+ OptimizedExpressionIndexOfArrayWithConstantArgumentsShouldEvaluateProperly) {
2291
+
2292
+ intrusive_ptr<ExpressionContextForTest> expCtx (new ExpressionContextForTest ());
2293
+
2294
+ auto expIndexOfArray = Expression::parseExpression (
2295
+ expCtx,
2296
+ // Search for $x.
2297
+ fromjson (" { $indexOfArray : [ [0, 1, 2, 3, 4, 5, 'val'] , '$x'] }" ),
2298
+ expCtx->variablesParseState );
2299
+ auto optimizedIndexOfArray = expIndexOfArray->optimize ();
2300
+ ASSERT_VALUE_EQ (Value (0 ), optimizedIndexOfArray->evaluate (Document{{" x" , 0 }}));
2301
+ ASSERT_VALUE_EQ (Value (1 ), optimizedIndexOfArray->evaluate (Document{{" x" , 1 }}));
2302
+ ASSERT_VALUE_EQ (Value (2 ), optimizedIndexOfArray->evaluate (Document{{" x" , 2 }}));
2303
+ ASSERT_VALUE_EQ (Value (3 ), optimizedIndexOfArray->evaluate (Document{{" x" , 3 }}));
2304
+ ASSERT_VALUE_EQ (Value (4 ), optimizedIndexOfArray->evaluate (Document{{" x" , 4 }}));
2305
+ ASSERT_VALUE_EQ (Value (5 ), optimizedIndexOfArray->evaluate (Document{{" x" , 5 }}));
2306
+ ASSERT_VALUE_EQ (Value (6 ), optimizedIndexOfArray->evaluate (Document{{" x" , string (" val" )}}));
2307
+
2308
+ auto optimizedIndexNotFound = optimizedIndexOfArray->optimize ();
2309
+ // Should evaluate to -1 if not found.
2310
+ ASSERT_VALUE_EQ (Value (-1 ), optimizedIndexNotFound->evaluate (Document{{" x" , 10 }}));
2311
+ ASSERT_VALUE_EQ (Value (-1 ), optimizedIndexNotFound->evaluate (Document{{" x" , 100 }}));
2312
+ ASSERT_VALUE_EQ (Value (-1 ), optimizedIndexNotFound->evaluate (Document{{" x" , 1000 }}));
2313
+ ASSERT_VALUE_EQ (Value (-1 ), optimizedIndexNotFound->evaluate (Document{{" x" , string (" string" )}}));
2314
+ ASSERT_VALUE_EQ (Value (-1 ), optimizedIndexNotFound->evaluate (Document{{" x" , -1 }}));
2315
+ }
2316
+
2317
+ TEST (ExpressionIndexOfArray,
2318
+ OptimizedExpressionIndexOfArrayWithConstantArgumentsShouldEvaluateProperlyWithRange) {
2319
+ intrusive_ptr<ExpressionContextForTest> expCtx (new ExpressionContextForTest ());
2320
+
2321
+ auto expIndexOfArray = Expression::parseExpression (
2322
+ expCtx,
2323
+ // Search for 4 between 3 and 5.
2324
+ fromjson (" { $indexOfArray : [ [0, 1, 2, 3, 4, 5] , '$x', 3, 5] }" ),
2325
+ expCtx->variablesParseState );
2326
+ auto optimizedIndexOfArray = expIndexOfArray->optimize ();
2327
+ ASSERT_VALUE_EQ (Value (4 ), optimizedIndexOfArray->evaluate (Document{{" x" , 4 }}));
2328
+
2329
+ // Should evaluate to -1 if not found in range.
2330
+ ASSERT_VALUE_EQ (Value (-1 ), optimizedIndexOfArray->evaluate (Document{{" x" , 0 }}));
2331
+ }
2332
+
2333
+ TEST (ExpressionIndexOfArray,
2334
+ OptimizedExpressionIndexOfArrayWithConstantArrayShouldEvaluateProperlyWithDuplicateValues) {
2335
+ intrusive_ptr<ExpressionContextForTest> expCtx (new ExpressionContextForTest ());
2336
+
2337
+ auto expIndexOfArrayWithDuplicateValues =
2338
+ Expression::parseExpression (expCtx,
2339
+ // Search for 4 between 3 and 5.
2340
+ fromjson (" { $indexOfArray : [ [0, 1, 2, 2, 3, 4, 5] , '$x'] }" ),
2341
+ expCtx->variablesParseState );
2342
+ auto optimizedIndexOfArrayWithDuplicateValues = expIndexOfArrayWithDuplicateValues->optimize ();
2343
+ ASSERT_VALUE_EQ (Value (2 ),
2344
+ optimizedIndexOfArrayWithDuplicateValues->evaluate (Document{{" x" , 2 }}));
2345
+ // Duplicate Values in a range.
2346
+ auto expIndexInRangeWithhDuplicateValues = Expression::parseExpression (
2347
+ expCtx,
2348
+ // Search for 2 between 4 and 6.
2349
+ fromjson (" { $indexOfArray : [ [0, 1, 2, 2, 2, 2, 4, 5] , '$x', 4, 6] }" ),
2350
+ expCtx->variablesParseState );
2351
+ auto optimizedIndexInRangeWithDuplcateValues = expIndexInRangeWithhDuplicateValues->optimize ();
2352
+ // Should evaluate to 4.
2353
+ ASSERT_VALUE_EQ (Value (4 ),
2354
+ optimizedIndexInRangeWithDuplcateValues->evaluate (Document{{" x" , 2 }}));
2355
+ }
2356
+
2211
2357
namespace FieldPath {
2212
2358
2213
2359
/* * The provided field path does not pass validation. */
0 commit comments