From 6d149c5cb89ee95eac52689466bd80b46b9e26ec Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 31 Aug 2025 16:22:09 +0300 Subject: [PATCH 1/6] Add test for count method in MongoDB integration This commit introduces a new test case in MongoTest.php to validate the functionality of the count method in the database. The test covers various scenarios including total count, filtered counts, counts with limits, and aggregation counts, ensuring comprehensive coverage of the counting capabilities. --- src/Client.php | 32 +++++++++++++++++--- tests/MongoTest.php | 71 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 4 deletions(-) diff --git a/src/Client.php b/src/Client.php index 975d624..095d155 100644 --- a/src/Client.php +++ b/src/Client.php @@ -707,10 +707,34 @@ public function delete(string $collection, array $filters = [], int $limit = 1, */ public function count(string $collection, array $filters, array $options): int { - $result = $this->find($collection, $filters, $options); - $list = $result->cursor->firstBatch; - - return \count($list); + + // Use MongoDB's native count command with the working format instad of running find and count the results + $command = [ + self::COMMAND_COUNT => $collection, + 'query' => $this->toObject($filters), + ]; + + // Add limit if specified + if (isset($options['limit'])) { + $command['limit'] = (int)$options['limit']; + } + + // Add skip if specified + if (isset($options['skip'])) { + $command['skip'] = (int)$options['skip']; + } + + // Add maxTimeMS if specified + if (isset($options['maxTimeMS'])) { + $command['maxTimeMS'] = (int)$options['maxTimeMS']; + } + + try { + $result = $this->query($command); + return (int)$result; + } catch (Exception $e) { + return 0; + } } /** diff --git a/tests/MongoTest.php b/tests/MongoTest.php index aba9be3..1337d03 100644 --- a/tests/MongoTest.php +++ b/tests/MongoTest.php @@ -261,4 +261,75 @@ public function testUpsert() self::assertEquals('USA', $documents[1]->country); self::assertEquals('English', $documents[1]->language); } + + public function testCountMethod() + { + + $collectionName = 'count_test'; + $this->getDatabase()->createCollection($collectionName); + + $documents = []; + for ($i = 1; $i <= 30; $i++) { + $documents[] = [ + 'name' => "Document {$i}", + 'number' => $i, + 'category' => 'test', + 'created_at' => new \DateTime() + ]; + } + + $this->getDatabase()->insertMany($collectionName, $documents); + + $total = $this->getDatabase()->count($collectionName, [], []); + self::assertEquals(30, $total); + + // Test count with filter (should be 1 for each specific number) + $total = $this->getDatabase()->count($collectionName, ['number' => 15], []); + self::assertEquals(1, $total); + + // Test count with range filter (should be 10 for numbers 1-10) + $total = $this->getDatabase()->count($collectionName, ['number' => ['$lte' => 10]], []); + self::assertEquals(10, $total); + + // Test count with limit (should be 5 for first 5 documents) + $total = $this->getDatabase()->count($collectionName, [], ['limit' => 5]); + self::assertEquals(5, $total); + + // Test count with filter and limit (should be 3 for first 3 documents with number <= 10) + $total = $this->getDatabase()->count($collectionName, ['number' => ['$lte' => 10]], ['limit' => 3]); + self::assertEquals(3, $total); + + // Test aggregation count - total documents + $aggregationResult = $this->getDatabase()->aggregate($collectionName, [ + ['$count' => 'total'] + ]); + self::assertEquals(30, $aggregationResult->cursor->firstBatch[0]->total); + + // Test aggregation count with filter + $filteredAggregationResult = $this->getDatabase()->aggregate($collectionName, [ + ['$match' => ['number' => ['$lte' => 10]]], + ['$count' => 'total'] + ]); + self::assertEquals(10, $filteredAggregationResult->cursor->firstBatch[0]->total); + + // Test aggregation count with limit + $limitedAggregationResult = $this->getDatabase()->aggregate($collectionName, [ + ['$limit' => 7], + ['$count' => 'total'] + ]); + self::assertEquals(7, $limitedAggregationResult->cursor->firstBatch[0]->total); + + // Test aggregation count with group by + $groupedAggregationResult = $this->getDatabase()->aggregate($collectionName, [ + ['$group' => [ + '_id' => '$category', // Group by category + 'count' => ['$sum' => 1] // Count of documents in the group + ]] + ]); + self::assertEquals(30, $groupedAggregationResult->cursor->firstBatch[0]->count); + self::assertEquals('test', $groupedAggregationResult->cursor->firstBatch[0]->_id); + + + $this->getDatabase()->dropCollection($collectionName); + } } From f2b48fae322618430f672f9174e1dd677243828f Mon Sep 17 00:00:00 2001 From: shimon Date: Thu, 11 Sep 2025 13:59:50 +0300 Subject: [PATCH 2/6] linter --- src/Client.php | 11 +++++------ tests/MongoTest.php | 29 ++++++++++++++--------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/Client.php b/src/Client.php index 095d155..dad2326 100644 --- a/src/Client.php +++ b/src/Client.php @@ -707,7 +707,6 @@ public function delete(string $collection, array $filters = [], int $limit = 1, */ public function count(string $collection, array $filters, array $options): int { - // Use MongoDB's native count command with the working format instad of running find and count the results $command = [ self::COMMAND_COUNT => $collection, @@ -718,20 +717,20 @@ public function count(string $collection, array $filters, array $options): int if (isset($options['limit'])) { $command['limit'] = (int)$options['limit']; } - + // Add skip if specified if (isset($options['skip'])) { $command['skip'] = (int)$options['skip']; } - + // Add maxTimeMS if specified if (isset($options['maxTimeMS'])) { $command['maxTimeMS'] = (int)$options['maxTimeMS']; } - + try { - $result = $this->query($command); - return (int)$result; + $result = $this->query($command); + return (int)$result; } catch (Exception $e) { return 0; } diff --git a/tests/MongoTest.php b/tests/MongoTest.php index 1337d03..a813ab0 100644 --- a/tests/MongoTest.php +++ b/tests/MongoTest.php @@ -264,10 +264,9 @@ public function testUpsert() public function testCountMethod() { - $collectionName = 'count_test'; $this->getDatabase()->createCollection($collectionName); - + $documents = []; for ($i = 1; $i <= 30; $i++) { $documents[] = [ @@ -277,48 +276,48 @@ public function testCountMethod() 'created_at' => new \DateTime() ]; } - + $this->getDatabase()->insertMany($collectionName, $documents); - + $total = $this->getDatabase()->count($collectionName, [], []); self::assertEquals(30, $total); - + // Test count with filter (should be 1 for each specific number) $total = $this->getDatabase()->count($collectionName, ['number' => 15], []); self::assertEquals(1, $total); - + // Test count with range filter (should be 10 for numbers 1-10) $total = $this->getDatabase()->count($collectionName, ['number' => ['$lte' => 10]], []); self::assertEquals(10, $total); - + // Test count with limit (should be 5 for first 5 documents) $total = $this->getDatabase()->count($collectionName, [], ['limit' => 5]); self::assertEquals(5, $total); - - // Test count with filter and limit (should be 3 for first 3 documents with number <= 10) + + // Test count with filter and limit (should be 3 for first 3 documents with number <= 10) $total = $this->getDatabase()->count($collectionName, ['number' => ['$lte' => 10]], ['limit' => 3]); self::assertEquals(3, $total); - + // Test aggregation count - total documents $aggregationResult = $this->getDatabase()->aggregate($collectionName, [ ['$count' => 'total'] ]); self::assertEquals(30, $aggregationResult->cursor->firstBatch[0]->total); - + // Test aggregation count with filter $filteredAggregationResult = $this->getDatabase()->aggregate($collectionName, [ ['$match' => ['number' => ['$lte' => 10]]], ['$count' => 'total'] ]); self::assertEquals(10, $filteredAggregationResult->cursor->firstBatch[0]->total); - + // Test aggregation count with limit $limitedAggregationResult = $this->getDatabase()->aggregate($collectionName, [ ['$limit' => 7], ['$count' => 'total'] ]); self::assertEquals(7, $limitedAggregationResult->cursor->firstBatch[0]->total); - + // Test aggregation count with group by $groupedAggregationResult = $this->getDatabase()->aggregate($collectionName, [ ['$group' => [ @@ -328,8 +327,8 @@ public function testCountMethod() ]); self::assertEquals(30, $groupedAggregationResult->cursor->firstBatch[0]->count); self::assertEquals('test', $groupedAggregationResult->cursor->firstBatch[0]->_id); - - + + $this->getDatabase()->dropCollection($collectionName); } } From 7189b96598fa6980e890c3d1a1ecd04c8432ce41 Mon Sep 17 00:00:00 2001 From: shimon Date: Thu, 11 Sep 2025 15:48:48 +0300 Subject: [PATCH 3/6] Enhance count method in Client class and expand test coverage This commit updates the count method in the Client class to include a call to cleanFilters for improved filter handling. Additionally, it adds new test cases in MongoTest.php to validate counting with the $or operator and complex conditions, ensuring robust testing of the counting functionality. --- src/Client.php | 5 ++++- tests/MongoTest.php | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Client.php b/src/Client.php index dad2326..f201ba2 100644 --- a/src/Client.php +++ b/src/Client.php @@ -707,12 +707,15 @@ public function delete(string $collection, array $filters = [], int $limit = 1, */ public function count(string $collection, array $filters, array $options): int { + + $filters = $this->cleanFilters($filters); + // Use MongoDB's native count command with the working format instad of running find and count the results $command = [ self::COMMAND_COUNT => $collection, 'query' => $this->toObject($filters), ]; - + var_dump($command); // Add limit if specified if (isset($options['limit'])) { $command['limit'] = (int)$options['limit']; diff --git a/tests/MongoTest.php b/tests/MongoTest.php index a813ab0..60837a4 100644 --- a/tests/MongoTest.php +++ b/tests/MongoTest.php @@ -298,6 +298,11 @@ public function testCountMethod() $total = $this->getDatabase()->count($collectionName, ['number' => ['$lte' => 10]], ['limit' => 3]); self::assertEquals(3, $total); + + // Test count with $or operator and comparison (should be 2 documents with number <= 2 OR number >= 29) + $total = $this->getDatabase()->count($collectionName, ['$or' => [['number' => ['$lte' => 2]], ['number' => ['$gte' => 29]]]], []); + self::assertEquals(4, $total); + // Test aggregation count - total documents $aggregationResult = $this->getDatabase()->aggregate($collectionName, [ ['$count' => 'total'] @@ -328,6 +333,20 @@ public function testCountMethod() self::assertEquals(30, $groupedAggregationResult->cursor->firstBatch[0]->count); self::assertEquals('test', $groupedAggregationResult->cursor->firstBatch[0]->_id); + // Test aggregation count with $or operator + $orAggregationResult = $this->getDatabase()->aggregate($collectionName, [ + ['$match' => ['$or' => [['number' => 5], ['number' => 15], ['number' => 25]]]], + ['$count' => 'total'] + ]); + self::assertEquals(3, $orAggregationResult->cursor->firstBatch[0]->total); + + // Test aggregation count with complex $or and range + $complexOrAggregationResult = $this->getDatabase()->aggregate($collectionName, [ + ['$match' => ['$or' => [['number' => ['$lte' => 3]], ['number' => ['$gte' => 28]]]]], + ['$count' => 'total'] + ]); + self::assertEquals(6, $complexOrAggregationResult->cursor->firstBatch[0]->total); + $this->getDatabase()->dropCollection($collectionName); } From eebbd5bef42e83d0d3d2c6061ad3dbb102eed976 Mon Sep 17 00:00:00 2001 From: shimon Date: Thu, 11 Sep 2025 15:49:24 +0300 Subject: [PATCH 4/6] removed var_dump --- src/Client.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Client.php b/src/Client.php index f201ba2..361980c 100644 --- a/src/Client.php +++ b/src/Client.php @@ -707,7 +707,6 @@ public function delete(string $collection, array $filters = [], int $limit = 1, */ public function count(string $collection, array $filters, array $options): int { - $filters = $this->cleanFilters($filters); // Use MongoDB's native count command with the working format instad of running find and count the results @@ -715,7 +714,7 @@ public function count(string $collection, array $filters, array $options): int self::COMMAND_COUNT => $collection, 'query' => $this->toObject($filters), ]; - var_dump($command); + // Add limit if specified if (isset($options['limit'])) { $command['limit'] = (int)$options['limit']; From a582d06621b70586b691e56ae39caa7a7e8bd393 Mon Sep 17 00:00:00 2001 From: shimon Date: Thu, 11 Sep 2025 16:18:43 +0300 Subject: [PATCH 5/6] Refactor MongoTest to ensure collection cleanup with try-finally block This commit modifies the MongoTest class to wrap the collection drop operation in a try-finally block, ensuring that the collection is always dropped after the test execution, even if an exception occurs during the test. This enhances the reliability of the test environment. --- tests/MongoTest.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/MongoTest.php b/tests/MongoTest.php index 60837a4..61b6221 100644 --- a/tests/MongoTest.php +++ b/tests/MongoTest.php @@ -266,7 +266,7 @@ public function testCountMethod() { $collectionName = 'count_test'; $this->getDatabase()->createCollection($collectionName); - + try { $documents = []; for ($i = 1; $i <= 30; $i++) { $documents[] = [ @@ -347,7 +347,8 @@ public function testCountMethod() ]); self::assertEquals(6, $complexOrAggregationResult->cursor->firstBatch[0]->total); - - $this->getDatabase()->dropCollection($collectionName); + } finally { + $this->getDatabase()->dropCollection($collectionName); + } } } From 21384092fb8412c074dfff1ce5b22b8a8587197e Mon Sep 17 00:00:00 2001 From: shimon Date: Thu, 11 Sep 2025 16:21:11 +0300 Subject: [PATCH 6/6] linter --- tests/MongoTest.php | 159 ++++++++++++++++++++++---------------------- 1 file changed, 79 insertions(+), 80 deletions(-) diff --git a/tests/MongoTest.php b/tests/MongoTest.php index 61b6221..84ce193 100644 --- a/tests/MongoTest.php +++ b/tests/MongoTest.php @@ -267,86 +267,85 @@ public function testCountMethod() $collectionName = 'count_test'; $this->getDatabase()->createCollection($collectionName); try { - $documents = []; - for ($i = 1; $i <= 30; $i++) { - $documents[] = [ - 'name' => "Document {$i}", - 'number' => $i, - 'category' => 'test', - 'created_at' => new \DateTime() - ]; - } - - $this->getDatabase()->insertMany($collectionName, $documents); - - $total = $this->getDatabase()->count($collectionName, [], []); - self::assertEquals(30, $total); - - // Test count with filter (should be 1 for each specific number) - $total = $this->getDatabase()->count($collectionName, ['number' => 15], []); - self::assertEquals(1, $total); - - // Test count with range filter (should be 10 for numbers 1-10) - $total = $this->getDatabase()->count($collectionName, ['number' => ['$lte' => 10]], []); - self::assertEquals(10, $total); - - // Test count with limit (should be 5 for first 5 documents) - $total = $this->getDatabase()->count($collectionName, [], ['limit' => 5]); - self::assertEquals(5, $total); - - // Test count with filter and limit (should be 3 for first 3 documents with number <= 10) - $total = $this->getDatabase()->count($collectionName, ['number' => ['$lte' => 10]], ['limit' => 3]); - self::assertEquals(3, $total); - - - // Test count with $or operator and comparison (should be 2 documents with number <= 2 OR number >= 29) - $total = $this->getDatabase()->count($collectionName, ['$or' => [['number' => ['$lte' => 2]], ['number' => ['$gte' => 29]]]], []); - self::assertEquals(4, $total); - - // Test aggregation count - total documents - $aggregationResult = $this->getDatabase()->aggregate($collectionName, [ - ['$count' => 'total'] - ]); - self::assertEquals(30, $aggregationResult->cursor->firstBatch[0]->total); - - // Test aggregation count with filter - $filteredAggregationResult = $this->getDatabase()->aggregate($collectionName, [ - ['$match' => ['number' => ['$lte' => 10]]], - ['$count' => 'total'] - ]); - self::assertEquals(10, $filteredAggregationResult->cursor->firstBatch[0]->total); - - // Test aggregation count with limit - $limitedAggregationResult = $this->getDatabase()->aggregate($collectionName, [ - ['$limit' => 7], - ['$count' => 'total'] - ]); - self::assertEquals(7, $limitedAggregationResult->cursor->firstBatch[0]->total); - - // Test aggregation count with group by - $groupedAggregationResult = $this->getDatabase()->aggregate($collectionName, [ - ['$group' => [ - '_id' => '$category', // Group by category - 'count' => ['$sum' => 1] // Count of documents in the group - ]] - ]); - self::assertEquals(30, $groupedAggregationResult->cursor->firstBatch[0]->count); - self::assertEquals('test', $groupedAggregationResult->cursor->firstBatch[0]->_id); - - // Test aggregation count with $or operator - $orAggregationResult = $this->getDatabase()->aggregate($collectionName, [ - ['$match' => ['$or' => [['number' => 5], ['number' => 15], ['number' => 25]]]], - ['$count' => 'total'] - ]); - self::assertEquals(3, $orAggregationResult->cursor->firstBatch[0]->total); - - // Test aggregation count with complex $or and range - $complexOrAggregationResult = $this->getDatabase()->aggregate($collectionName, [ - ['$match' => ['$or' => [['number' => ['$lte' => 3]], ['number' => ['$gte' => 28]]]]], - ['$count' => 'total'] - ]); - self::assertEquals(6, $complexOrAggregationResult->cursor->firstBatch[0]->total); - + $documents = []; + for ($i = 1; $i <= 30; $i++) { + $documents[] = [ + 'name' => "Document {$i}", + 'number' => $i, + 'category' => 'test', + 'created_at' => new \DateTime() + ]; + } + + $this->getDatabase()->insertMany($collectionName, $documents); + + $total = $this->getDatabase()->count($collectionName, [], []); + self::assertEquals(30, $total); + + // Test count with filter (should be 1 for each specific number) + $total = $this->getDatabase()->count($collectionName, ['number' => 15], []); + self::assertEquals(1, $total); + + // Test count with range filter (should be 10 for numbers 1-10) + $total = $this->getDatabase()->count($collectionName, ['number' => ['$lte' => 10]], []); + self::assertEquals(10, $total); + + // Test count with limit (should be 5 for first 5 documents) + $total = $this->getDatabase()->count($collectionName, [], ['limit' => 5]); + self::assertEquals(5, $total); + + // Test count with filter and limit (should be 3 for first 3 documents with number <= 10) + $total = $this->getDatabase()->count($collectionName, ['number' => ['$lte' => 10]], ['limit' => 3]); + self::assertEquals(3, $total); + + + // Test count with $or operator and comparison (should be 2 documents with number <= 2 OR number >= 29) + $total = $this->getDatabase()->count($collectionName, ['$or' => [['number' => ['$lte' => 2]], ['number' => ['$gte' => 29]]]], []); + self::assertEquals(4, $total); + + // Test aggregation count - total documents + $aggregationResult = $this->getDatabase()->aggregate($collectionName, [ + ['$count' => 'total'] + ]); + self::assertEquals(30, $aggregationResult->cursor->firstBatch[0]->total); + + // Test aggregation count with filter + $filteredAggregationResult = $this->getDatabase()->aggregate($collectionName, [ + ['$match' => ['number' => ['$lte' => 10]]], + ['$count' => 'total'] + ]); + self::assertEquals(10, $filteredAggregationResult->cursor->firstBatch[0]->total); + + // Test aggregation count with limit + $limitedAggregationResult = $this->getDatabase()->aggregate($collectionName, [ + ['$limit' => 7], + ['$count' => 'total'] + ]); + self::assertEquals(7, $limitedAggregationResult->cursor->firstBatch[0]->total); + + // Test aggregation count with group by + $groupedAggregationResult = $this->getDatabase()->aggregate($collectionName, [ + ['$group' => [ + '_id' => '$category', // Group by category + 'count' => ['$sum' => 1] // Count of documents in the group + ]] + ]); + self::assertEquals(30, $groupedAggregationResult->cursor->firstBatch[0]->count); + self::assertEquals('test', $groupedAggregationResult->cursor->firstBatch[0]->_id); + + // Test aggregation count with $or operator + $orAggregationResult = $this->getDatabase()->aggregate($collectionName, [ + ['$match' => ['$or' => [['number' => 5], ['number' => 15], ['number' => 25]]]], + ['$count' => 'total'] + ]); + self::assertEquals(3, $orAggregationResult->cursor->firstBatch[0]->total); + + // Test aggregation count with complex $or and range + $complexOrAggregationResult = $this->getDatabase()->aggregate($collectionName, [ + ['$match' => ['$or' => [['number' => ['$lte' => 3]], ['number' => ['$gte' => 28]]]]], + ['$count' => 'total'] + ]); + self::assertEquals(6, $complexOrAggregationResult->cursor->firstBatch[0]->total); } finally { $this->getDatabase()->dropCollection($collectionName); }