From 39d0018b5ac7a088fbf9f0ba1fd2966d625422ed Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Thu, 11 Jun 2026 14:07:35 +0400 Subject: [PATCH] feat(SelectQuery): refine Psalm integer types on query bounds Express numeric bounds via Psalm types so static analysis flags invalid values at call sites: - runChunks() chunk size as int<1, max> (a non-positive value never advances the offset and spins in an endless loop); - getLimit() / getOffset() as int<0, max>|null; - count() as int<0, max> (a row count is never negative). Also drop the redundant `psalm-` prefix from the existing non-empty-string column/method hints: plain `@param` advanced types are now broadly supported (Psalm, PHPStan, PhpStorm). Return-type refinements only; LessSpecificReturnStatement / MoreSpecificReturnType are already suppressed project-wide, and setter params are left intact to preserve the PaginableInterface contract. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/Query/SelectQuery.php | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/Query/SelectQuery.php b/src/Query/SelectQuery.php index 0d80c809..0ab97d86 100644 --- a/src/Query/SelectQuery.php +++ b/src/Query/SelectQuery.php @@ -255,6 +255,9 @@ public function limit(?int $limit = null): self return $this; } + /** + * @return int<0, max>|null + */ public function getLimit(): ?int { return $this->limit; @@ -271,6 +274,9 @@ public function offset(?int $offset = null): self return $this; } + /** + * @return int<0, max>|null + */ public function getOffset(): ?int { return $this->offset; @@ -294,6 +300,8 @@ public function run(): StatementInterface * * You must return FALSE from walk function to stop chunking. * + * @param int<1, max> $limit Chunk size. + * * @throws \Throwable */ public function runChunks(int $limit, callable $callback): void @@ -324,7 +332,9 @@ public function runChunks(int $limit, callable $callback): void /** * Count number of rows in query. Limit, offset, order by, group by values will be ignored. * - * @psalm-param non-empty-string $column Column to count by (every column by default). + * @param non-empty-string $column Column to count by (every column by default). + * + * @return int<0, max> */ public function count(string $column = '*', bool $distinct = false): int { @@ -346,7 +356,7 @@ public function count(string $column = '*', bool $distinct = false): int } /** - * @psalm-param non-empty-string $column + * @param non-empty-string $column */ public function avg(string $column): mixed { @@ -354,7 +364,7 @@ public function avg(string $column): mixed } /** - * @psalm-param non-empty-string $column + * @param non-empty-string $column */ public function max(string $column): mixed { @@ -362,7 +372,7 @@ public function max(string $column): mixed } /** - * @psalm-param non-empty-string $column + * @param non-empty-string $column */ public function min(string $column): mixed { @@ -370,7 +380,7 @@ public function min(string $column): mixed } /** - * @psalm-param non-empty-string $column + * @param non-empty-string $column */ public function sum(string $column): mixed { @@ -436,8 +446,8 @@ private function addOrder(string|FragmentInterface $field, ?string $order): self } /** - * @psalm-param non-empty-string $method - * @psalm-param non-empty-string $column + * @param non-empty-string $method + * @param non-empty-string $column */ private function runAggregate(string $method, string $column): mixed {