|
11 | 11 | use Patchlevel\Rango\Collection as RangoCollection; |
12 | 12 | use Patchlevel\Rango\Database as RangoDatabase; |
13 | 13 | use PHPUnit\Framework\TestCase; |
| 14 | +use RuntimeException; |
14 | 15 |
|
15 | 16 | use function array_map; |
16 | 17 | use function array_values; |
@@ -80,6 +81,13 @@ public function testFindOne(): void |
80 | 81 | $this->assertEquals('foo', $doc['name']); |
81 | 82 | } |
82 | 83 |
|
| 84 | + public function testFindOneNotFound(): void |
| 85 | + { |
| 86 | + $doc = $this->collection->findOne(['_id' => 'missing']); |
| 87 | + |
| 88 | + $this->assertNull($doc); |
| 89 | + } |
| 90 | + |
83 | 91 | public function testUpdateOne(): void |
84 | 92 | { |
85 | 93 | $this->collection->insertOne(['_id' => '1', 'name' => 'foo']); |
@@ -144,6 +152,16 @@ public function testProjection(): void |
144 | 152 | $this->assertArrayNotHasKey('age', $doc); |
145 | 153 | } |
146 | 154 |
|
| 155 | + public function testProjectionExcludeId(): void |
| 156 | + { |
| 157 | + $this->collection->insertOne(['_id' => '1', 'name' => 'foo', 'age' => 42]); |
| 158 | + |
| 159 | + $doc = $this->collection->findOne(['_id' => '1'], ['projection' => ['name' => 1, '_id' => 0]]); |
| 160 | + $this->assertArrayHasKey('name', $doc); |
| 161 | + $this->assertArrayNotHasKey('_id', $doc); |
| 162 | + $this->assertArrayNotHasKey('age', $doc); |
| 163 | + } |
| 164 | + |
147 | 165 | public function testReplaceOne(): void |
148 | 166 | { |
149 | 167 | $this->collection->insertOne(['_id' => '1', 'name' => 'foo', 'age' => 42]); |
@@ -188,6 +206,17 @@ public function testComparisonOperators(): void |
188 | 206 | $this->assertCount(1, iterator_to_array($this->collection->find(['age' => ['$nin' => [20, 40]]]))); |
189 | 207 | } |
190 | 208 |
|
| 209 | + public function testInAndNinEmpty(): void |
| 210 | + { |
| 211 | + $this->collection->insertMany([ |
| 212 | + ['_id' => '1', 'age' => 20], |
| 213 | + ['_id' => '2', 'age' => 30], |
| 214 | + ]); |
| 215 | + |
| 216 | + $this->assertCount(0, iterator_to_array($this->collection->find(['age' => ['$in' => []]]))); |
| 217 | + $this->assertCount(2, iterator_to_array($this->collection->find(['age' => ['$nin' => []]]))); |
| 218 | + } |
| 219 | + |
191 | 220 | public function testLogicalOperators(): void |
192 | 221 | { |
193 | 222 | $this->collection->insertMany([ |
@@ -233,6 +262,18 @@ public function testExists(): void |
233 | 262 | $this->assertCount(1, iterator_to_array($this->collection->find(['name' => ['$exists' => false]]))); |
234 | 263 | } |
235 | 264 |
|
| 265 | + public function testExistsWithNull(): void |
| 266 | + { |
| 267 | + $this->collection->insertMany([ |
| 268 | + ['_id' => '1', 'name' => null], |
| 269 | + ['_id' => '2', 'name' => 'foo'], |
| 270 | + ['_id' => '3', 'age' => 30], |
| 271 | + ]); |
| 272 | + |
| 273 | + $this->assertCount(2, iterator_to_array($this->collection->find(['name' => ['$exists' => true]]))); |
| 274 | + $this->assertCount(1, iterator_to_array($this->collection->find(['name' => ['$exists' => false]]))); |
| 275 | + } |
| 276 | + |
236 | 277 | public function testUpsert(): void |
237 | 278 | { |
238 | 279 | $result = $this->collection->updateOne(['_id' => '1'], ['$set' => ['name' => 'foo']], ['upsert' => true]); |
@@ -391,6 +432,20 @@ public function testDistinct(): void |
391 | 432 | $this->assertEquals(['A', 'B'], $values); |
392 | 433 | } |
393 | 434 |
|
| 435 | + public function testDistinctWithFilter(): void |
| 436 | + { |
| 437 | + $this->collection->insertMany([ |
| 438 | + ['_id' => '1', 'category' => 'A', 'status' => 'open'], |
| 439 | + ['_id' => '2', 'category' => 'B', 'status' => 'closed'], |
| 440 | + ['_id' => '3', 'category' => 'A', 'status' => 'closed'], |
| 441 | + ]); |
| 442 | + |
| 443 | + $values = $this->collection->distinct('category', ['status' => 'closed']); |
| 444 | + sort($values); |
| 445 | + |
| 446 | + $this->assertEquals(['A', 'B'], $values); |
| 447 | + } |
| 448 | + |
394 | 449 | public function testPushAndPull(): void |
395 | 450 | { |
396 | 451 | $this->collection->insertOne(['_id' => '1', 'tags' => ['foo']]); |
@@ -900,6 +955,77 @@ public function testCombinedUpdate(): void |
900 | 955 | $this->assertEquals(['a', 'b'], (array)$doc['tags']); |
901 | 956 | } |
902 | 957 |
|
| 958 | + public function testIncCreatesField(): void |
| 959 | + { |
| 960 | + $this->collection->insertOne(['_id' => '1', 'name' => 'foo']); |
| 961 | + |
| 962 | + $this->collection->updateOne(['_id' => '1'], ['$inc' => ['counter' => 2]]); |
| 963 | + $doc = $this->collection->findOne(['_id' => '1']); |
| 964 | + |
| 965 | + $this->assertEquals(2, $doc['counter']); |
| 966 | + } |
| 967 | + |
| 968 | + public function testInvalidTopLevelOperatorThrows(): void |
| 969 | + { |
| 970 | + $this->collection->insertOne(['_id' => '1', 'name' => 'foo']); |
| 971 | + |
| 972 | + $this->expectException(RuntimeException::class); |
| 973 | + $this->collection->find(['$unknown' => ['name' => 'foo']]); |
| 974 | + } |
| 975 | + |
| 976 | + public function testInvalidInOperatorThrows(): void |
| 977 | + { |
| 978 | + $this->collection->insertOne(['_id' => '1', 'age' => 20]); |
| 979 | + |
| 980 | + $this->expectException(RuntimeException::class); |
| 981 | + $this->collection->find(['age' => ['$in' => 'not-an-array']]); |
| 982 | + } |
| 983 | + |
| 984 | + public function testInvalidModOperatorThrows(): void |
| 985 | + { |
| 986 | + $this->collection->insertOne(['_id' => '1', 'v' => 10]); |
| 987 | + |
| 988 | + $this->expectException(RuntimeException::class); |
| 989 | + $this->collection->find(['v' => ['$mod' => [2]]]); |
| 990 | + } |
| 991 | + |
| 992 | + public function testInvalidElemMatchThrows(): void |
| 993 | + { |
| 994 | + $this->collection->insertOne(['_id' => '1', 'tags' => ['a', 'b']]); |
| 995 | + |
| 996 | + $this->expectException(RuntimeException::class); |
| 997 | + $this->collection->find(['tags' => ['$elemMatch' => 'not-an-array']]); |
| 998 | + } |
| 999 | + |
| 1000 | + public function testUpdateWithoutOperatorsThrows(): void |
| 1001 | + { |
| 1002 | + $this->collection->insertOne(['_id' => '1', 'name' => 'foo']); |
| 1003 | + |
| 1004 | + $this->expectException($this->collection instanceof RangoCollection ? RuntimeException::class : \MongoDB\Exception\InvalidArgumentException::class); |
| 1005 | + $this->collection->updateOne(['_id' => '1'], []); |
| 1006 | + } |
| 1007 | + |
| 1008 | + public function testUpsertWithoutIdThrows(): void |
| 1009 | + { |
| 1010 | + if ($this->collection instanceof RangoCollection) { |
| 1011 | + $this->expectException(RuntimeException::class); |
| 1012 | + $this->collection->updateOne(['name' => 'foo'], ['$set' => ['name' => 'bar']], ['upsert' => true]); |
| 1013 | + |
| 1014 | + return; |
| 1015 | + } |
| 1016 | + |
| 1017 | + $result = $this->collection->updateOne(['name' => 'foo'], ['$set' => ['name' => 'bar']], ['upsert' => true]); |
| 1018 | + $this->assertEquals(1, $result->getUpsertedCount()); |
| 1019 | + $this->assertNotNull($result->getUpsertedId()); |
| 1020 | + } |
| 1021 | + |
| 1022 | + public function testInvalidBitOperatorThrows(): void |
| 1023 | + { |
| 1024 | + $this->collection->insertOne(['_id' => '1', 'v' => 10]); |
| 1025 | + |
| 1026 | + $this->expectException(RuntimeException::class); |
| 1027 | + $this->collection->updateOne(['_id' => '1'], ['$bit' => ['v' => ['invalid' => 1]]]); |
| 1028 | + } |
903 | 1029 | public function testElemMatchComplex(): void |
904 | 1030 | { |
905 | 1031 | $this->collection->insertMany([ |
|
0 commit comments