Skip to content

Commit

Permalink
Support counting the rows that match a filter without selecting them
Browse files Browse the repository at this point in the history
  • Loading branch information
theodorejb committed Dec 22, 2023
1 parent 00f6580 commit 8315493
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 1 deletion.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [2.8.0] - 2023-12-22
### Added
- `countEntities()` method and corresponding `count()` route handler.
This allows counting the rows that match a query/filter without selecting them.

## [2.7.0] - 2023-09-27
### Added
- `writableId` bool property to optionally make the ID column writable.
Expand Down Expand Up @@ -146,7 +151,8 @@ return early if passed an empty IDs array.
### Changed
- Initial stable release

[Unreleased]: https://github.com/theodorejb/phaster/compare/v2.7.0...HEAD
[Unreleased]: https://github.com/theodorejb/phaster/compare/v2.8.0...HEAD
[2.8.0]: https://github.com/theodorejb/phaster/compare/v2.7.0...v2.8.0
[2.7.0]: https://github.com/theodorejb/phaster/compare/v2.6.0...v2.7.0
[2.6.0]: https://github.com/theodorejb/phaster/compare/v2.5.0...v2.6.0
[2.5.0]: https://github.com/theodorejb/phaster/compare/v2.4.0...v2.5.0
Expand Down
18 changes: 18 additions & 0 deletions src/Entities.php
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,24 @@ public function getEntities(array $filter = [], array $fields = [], array $sort
return Helpers::mapRows($select->query()->getIterator(), $fieldProps);
}

public function countEntities(array $filter = []): int
{
$processedFilter = $this->processFilter($filter);
$selectMap = Helpers::propMapToSelectMap($this->fullPropMap);;

$prop = new Prop('count', 'COUNT(*)', false, true, 'count');
$queryOptions = new QueryOptions($processedFilter, $filter, [], [$prop]);

/** @psalm-suppress MixedArgumentTypeCoercion */
$select = $this->db->select($this->getBaseSelect($queryOptions))
->where(self::propertiesToColumns($selectMap, $processedFilter));

/** @var array{count: int} $row */
$row = $select->query()->getFirst();

return $row['count'];
}

/**
* Converts nested properties to an array of columns and values using a map.
* @return array<string, mixed>
Expand Down
29 changes: 29 additions & 0 deletions src/RouteHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,35 @@ public function search(string $class, int $defaultLimit = 25, int $maxLimit = 10
};
}

/**
* @param class-string<Entities> $class
*/
public function count(string $class): callable
{
$factory = $this->entitiesFactory;

return function (ServerRequestInterface $request, ResponseInterface $response) use ($class, $factory): ResponseInterface {
$query = [];

foreach ($request->getQueryParams() as $param => $value) {
if ($param !== 'q') {
throw new HttpException("Unrecognized parameter '{$param}'", StatusCode::BAD_REQUEST);
}
if (!is_array($value)) {
throw new HttpException("Parameter '{$param}' must be an array", StatusCode::BAD_REQUEST);
}

$query = $value;
}

$instance = $factory->createEntities($class);
$count = $instance->countEntities($query);

$response->getBody()->write(json_encode(['count' => $count]));
return $response->withHeader('Content-Type', 'application/json');
};
}

/**
* @param class-string<Entities> $class
*/
Expand Down
20 changes: 20 additions & 0 deletions test/EntitiesDbTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,26 @@ public function testGetEntities(Entities $entities): void
$this->assertSame($expected, $actual);
}

/**
* @dataProvider entitiesProvider
*/
public function testCountEntities(Entities $entities): void
{
$users = [];

for ($i = 1; $i <= 20; $i++) {
$users[] = [
'name' => "Count user {$i}",
'birthday' => '2000-03-04',
'weight' => $i * 10,
];
}

$entities->addEntities($users);
$actual = $entities->countEntities(['weight' => ['le' => 100], 'name' => ['lk' => 'Count user %']]);
$this->assertSame(10, $actual);
}

/**
* @dataProvider legacyUsersProvider
*/
Expand Down

0 comments on commit 8315493

Please sign in to comment.