@@ -1188,7 +1188,7 @@ public function testSchemalessExists(): void
11881188
11891189 // Test exists - should return documents where optionalField exists (even if null)
11901190 $ documents = $ database ->find ($ colName , [
1191- Query::exists ('optionalField ' ),
1191+ Query::exists ([ 'optionalField ' ] ),
11921192 ]);
11931193
11941194 $ this ->assertEquals (3 , count ($ documents )); // doc1, doc2, doc4
@@ -1205,13 +1205,68 @@ public function testSchemalessExists(): void
12051205
12061206 // Test exists with another attribute
12071207 $ documents = $ database ->find ($ colName , [
1208- Query::exists ('name ' ),
1208+ Query::exists ([ 'name ' ] ),
12091209 ]);
12101210 $ this ->assertEquals (5 , count ($ documents )); // All documents have 'name'
12111211
12121212 // Test exists with non-existent attribute
12131213 $ documents = $ database ->find ($ colName , [
1214- Query::exists ('nonExistentField ' ),
1214+ Query::exists (['nonExistentField ' ]),
1215+ ]);
1216+ $ this ->assertEquals (0 , count ($ documents ));
1217+
1218+ // Multiple attributes in a single exists query (OR semantics)
1219+ $ documents = $ database ->find ($ colName , [
1220+ Query::exists (['optionalField ' , 'name ' ]),
1221+ ]);
1222+ // All documents have "name", some also have "optionalField"
1223+ $ this ->assertEquals (5 , count ($ documents ));
1224+
1225+ // Multiple attributes where only one exists on some documents
1226+ $ documents = $ database ->find ($ colName , [
1227+ Query::exists (['optionalField ' , 'nonExistentField ' ]),
1228+ ]);
1229+ // Only documents where optionalField exists should be returned
1230+ $ this ->assertEquals (3 , count ($ documents )); // doc1, doc2, doc4
1231+
1232+ // Multiple attributes where none exist should return empty
1233+ $ documents = $ database ->find ($ colName , [
1234+ Query::exists (['nonExistentField ' , 'alsoMissing ' ]),
1235+ ]);
1236+ $ this ->assertEquals (0 , count ($ documents ));
1237+
1238+ // Multiple attributes including one present on all docs still returns all (OR)
1239+ $ documents = $ database ->find ($ colName , [
1240+ Query::exists (['name ' , 'nonExistentField ' , 'alsoMissing ' ]),
1241+ ]);
1242+ $ this ->assertEquals (5 , count ($ documents ));
1243+
1244+ // Multiple exists queries (AND semantics)
1245+ $ documents = $ database ->find ($ colName , [
1246+ Query::exists (['optionalField ' ]),
1247+ Query::exists (['name ' ]),
1248+ ]);
1249+ // Documents must have both attributes
1250+ $ this ->assertEquals (3 , count ($ documents )); // doc1, doc2, doc4
1251+
1252+ // Nested OR with exists (optionalField OR nonExistentField) AND name
1253+ $ documents = $ database ->find ($ colName , [
1254+ Query::and ([
1255+ Query::or ([
1256+ Query::exists (['optionalField ' ]),
1257+ Query::exists (['nonExistentField ' ]),
1258+ ]),
1259+ Query::exists (['name ' ]),
1260+ ]),
1261+ ]);
1262+ $ this ->assertEquals (3 , count ($ documents )); // doc1, doc2, doc4
1263+
1264+ // Nested OR with only missing attributes should yield empty
1265+ $ documents = $ database ->find ($ colName , [
1266+ Query::or ([
1267+ Query::exists (['nonExistentField ' ]),
1268+ Query::exists (['alsoMissing ' ]),
1269+ ]),
12151270 ]);
12161271 $ this ->assertEquals (0 , count ($ documents ));
12171272
@@ -1273,13 +1328,54 @@ public function testSchemalessNotExists(): void
12731328 ]);
12741329 $ this ->assertEquals (5 , count ($ documents )); // All documents don't have this field
12751330
1331+ // Multiple attributes in a single notExists query (OR semantics) - both missing
1332+ $ documents = $ database ->find ($ colName , [
1333+ Query::notExists (['nonExistentField ' , 'alsoMissing ' ]),
1334+ ]);
1335+ $ this ->assertEquals (5 , count ($ documents ));
1336+
1337+ // Multiple attributes (OR) where only some documents miss one of them
1338+ $ documents = $ database ->find ($ colName , [
1339+ Query::notExists (['name ' , 'optionalField ' ]),
1340+ ]);
1341+ $ this ->assertEquals (2 , count ($ documents )); // doc3, doc5
1342+
1343+ // Multiple notExists queries (AND semantics) - must miss both
1344+ $ documents = $ database ->find ($ colName , [
1345+ Query::notExists (['optionalField ' ]),
1346+ Query::notExists (['nonExistentField ' ]),
1347+ ]);
1348+ $ this ->assertEquals (2 , count ($ documents )); // doc3, doc5
1349+
12761350 // Test combination of exists and notExists
12771351 $ documents = $ database ->find ($ colName , [
1278- Query::exists ('name ' ),
1352+ Query::exists ([ 'name ' ] ),
12791353 Query::notExists ('optionalField ' ),
12801354 ]);
12811355 $ this ->assertEquals (2 , count ($ documents )); // doc3, doc5
12821356
1357+ // Nested OR/AND with notExists: (notExists optionalField OR notExists nonExistent) AND name
1358+ $ documents = $ database ->find ($ colName , [
1359+ Query::and ([
1360+ Query::or ([
1361+ Query::notExists (['optionalField ' ]),
1362+ Query::notExists (['nonExistentField ' ]),
1363+ ]),
1364+ Query::exists (['name ' ]),
1365+ ]),
1366+ ]);
1367+ // notExists(nonExistentField) matches all docs, so OR is always true; AND with name returns all
1368+ $ this ->assertEquals (5 , count ($ documents )); // all docs match due to nonExistentField
1369+
1370+ // Nested OR with notExists where all attributes exist => empty
1371+ $ documents = $ database ->find ($ colName , [
1372+ Query::or ([
1373+ Query::notExists (['name ' ]),
1374+ Query::notExists (['optionalField ' ]),
1375+ ]),
1376+ ]);
1377+ $ this ->assertEquals (2 , count ($ documents )); // only ones missing optionalField (doc3, doc5)
1378+
12831379 $ database ->deleteCollection ($ colName );
12841380 }
12851381}
0 commit comments