From 2fd795365c34d2012a48152574972352169ae196 Mon Sep 17 00:00:00 2001 From: Tigrov Date: Mon, 15 Jun 2026 14:37:55 +0700 Subject: [PATCH 1/5] Add `getBounds()` method to range values --- src/Expression/DateRangeValue.php | 13 +++++++++++++ src/Expression/Int4RangeValue.php | 13 +++++++++++++ src/Expression/Int8RangeValue.php | 13 +++++++++++++ src/Expression/NumRangeValue.php | 18 ++++++++++++++++++ src/Expression/TsRangeValue.php | 13 +++++++++++++ src/Expression/TsTzRangeValue.php | 13 +++++++++++++ 6 files changed, 83 insertions(+) diff --git a/src/Expression/DateRangeValue.php b/src/Expression/DateRangeValue.php index 9fa76d548..69da6f98f 100644 --- a/src/Expression/DateRangeValue.php +++ b/src/Expression/DateRangeValue.php @@ -15,4 +15,17 @@ public function __construct( public readonly bool $includeLower = true, public readonly bool $includeUpper = true, ) {} + + public function getBounds(): array + { + $lower = $this->lower === null || $this->includeLower + ? $this->lower + : $this->lower->modify('+1 day'); + + $upper = $this->upper === null || $this->includeUpper + ? $this->upper + : $this->upper->modify('-1 day'); + + return [$lower, $upper]; + } } diff --git a/src/Expression/Int4RangeValue.php b/src/Expression/Int4RangeValue.php index d65c6efde..755c64514 100644 --- a/src/Expression/Int4RangeValue.php +++ b/src/Expression/Int4RangeValue.php @@ -14,4 +14,17 @@ public function __construct( public readonly bool $includeLower = true, public readonly bool $includeUpper = true, ) {} + + public function getBounds(): array + { + $lower = $this->lower === null || $this->includeLower + ? $this->lower + : $this->lower + 1; + + $upper = $this->upper === null || $this->includeUpper + ? $this->upper + : $this->upper - 1; + + return [$lower, $upper]; + } } diff --git a/src/Expression/Int8RangeValue.php b/src/Expression/Int8RangeValue.php index 903425569..7a152f354 100644 --- a/src/Expression/Int8RangeValue.php +++ b/src/Expression/Int8RangeValue.php @@ -14,4 +14,17 @@ public function __construct( public readonly bool $includeLower = true, public readonly bool $includeUpper = true, ) {} + + public function getBounds(): array + { + $lower = $this->lower === null || $this->includeLower + ? $this->lower + : $this->lower + 1; + + $upper = $this->upper === null || $this->includeUpper + ? $this->upper + : $this->upper - 1; + + return [$lower, $upper]; + } } diff --git a/src/Expression/NumRangeValue.php b/src/Expression/NumRangeValue.php index 1f5d3f234..397164092 100644 --- a/src/Expression/NumRangeValue.php +++ b/src/Expression/NumRangeValue.php @@ -5,6 +5,7 @@ namespace Yiisoft\Db\Pgsql\Expression; use Yiisoft\Db\Expression\ExpressionInterface; +use RuntimeException; final class NumRangeValue implements ExpressionInterface { @@ -14,4 +15,21 @@ public function __construct( public readonly bool $includeLower = true, public readonly bool $includeUpper = true, ) {} + + public function getBounds(): array + { + $lower = $this->lower === null || $this->includeLower + ? $this->lower + : throw new RuntimeException( + 'Lower bound cannot be determined from the excluded values of a numeric range.', + ); + + $upper = $this->upper === null || $this->includeUpper + ? $this->upper + : throw new RuntimeException( + 'Upper bound cannot be determined from the excluded values of a numeric range.', + ); + + return [$lower, $upper]; + } } diff --git a/src/Expression/TsRangeValue.php b/src/Expression/TsRangeValue.php index 50594c8e9..5c5afd44c 100644 --- a/src/Expression/TsRangeValue.php +++ b/src/Expression/TsRangeValue.php @@ -15,4 +15,17 @@ public function __construct( public readonly bool $includeLower = true, public readonly bool $includeUpper = true, ) {} + + public function getBounds(): array + { + $lower = $this->lower === null || $this->includeLower + ? $this->lower + : $this->lower->modify('+1 second'); + + $upper = $this->upper === null || $this->includeUpper + ? $this->upper + : $this->upper->modify('-1 second'); + + return [$lower, $upper]; + } } diff --git a/src/Expression/TsTzRangeValue.php b/src/Expression/TsTzRangeValue.php index 7f08c3aab..be9c85cf3 100644 --- a/src/Expression/TsTzRangeValue.php +++ b/src/Expression/TsTzRangeValue.php @@ -15,4 +15,17 @@ public function __construct( public readonly bool $includeLower = true, public readonly bool $includeUpper = true, ) {} + + public function getBounds(): array + { + $lower = $this->lower === null || $this->includeLower + ? $this->lower + : $this->lower->modify('+1 second'); + + $upper = $this->upper === null || $this->includeUpper + ? $this->upper + : $this->upper->modify('-1 second'); + + return [$lower, $upper]; + } } From 6cf8bfe98502b1f65add5ae0746be73686204354 Mon Sep 17 00:00:00 2001 From: Tigrov Date: Mon, 15 Jun 2026 14:54:27 +0700 Subject: [PATCH 2/5] Improve --- src/Expression/Int8RangeValue.php | 16 ++++++++++++++-- src/Expression/NumRangeValue.php | 4 ++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/Expression/Int8RangeValue.php b/src/Expression/Int8RangeValue.php index 7a152f354..b5ec48b36 100644 --- a/src/Expression/Int8RangeValue.php +++ b/src/Expression/Int8RangeValue.php @@ -5,6 +5,10 @@ namespace Yiisoft\Db\Pgsql\Expression; use Yiisoft\Db\Expression\ExpressionInterface; +use InvalidArgumentException; + +use const PHP_INT_MAX; +use const PHP_INT_MIN; final class Int8RangeValue implements ExpressionInterface { @@ -19,11 +23,19 @@ public function getBounds(): array { $lower = $this->lower === null || $this->includeLower ? $this->lower - : $this->lower + 1; + : ( + PHP_INT_MIN <= $this->lower && $this->lower < PHP_INT_MAX + ? (int) $this->lower + 1 + : throw new InvalidArgumentException('Lower bound cannot be determined from the excluded value of a bigint range.') + ); $upper = $this->upper === null || $this->includeUpper ? $this->upper - : $this->upper - 1; + : ( + PHP_INT_MIN < $this->upper && $this->upper <= PHP_INT_MAX + ? (int) $this->upper - 1 + : throw new InvalidArgumentException('Upper bound cannot be determined from the excluded value of a bigint range.') + ); return [$lower, $upper]; } diff --git a/src/Expression/NumRangeValue.php b/src/Expression/NumRangeValue.php index 397164092..25e44bd1c 100644 --- a/src/Expression/NumRangeValue.php +++ b/src/Expression/NumRangeValue.php @@ -21,13 +21,13 @@ public function getBounds(): array $lower = $this->lower === null || $this->includeLower ? $this->lower : throw new RuntimeException( - 'Lower bound cannot be determined from the excluded values of a numeric range.', + 'Lower bound cannot be determined from the excluded value of a numeric range.', ); $upper = $this->upper === null || $this->includeUpper ? $this->upper : throw new RuntimeException( - 'Upper bound cannot be determined from the excluded values of a numeric range.', + 'Upper bound cannot be determined from the excluded value of a numeric range.', ); return [$lower, $upper]; From 52adac652e7995863959c75ec68cd7058d96c671 Mon Sep 17 00:00:00 2001 From: Tigrov Date: Mon, 15 Jun 2026 21:14:35 +0700 Subject: [PATCH 3/5] Add `RangeValueInterface` --- src/Column/AbstractMultiRangeColumn.php | 5 +++-- src/Column/AbstractRangeColumn.php | 7 +++++-- src/Expression/DateRangeValue.php | 6 ++++-- src/Expression/Int4RangeValue.php | 7 ++++--- src/Expression/Int8RangeValue.php | 6 ++++-- src/Expression/NumRangeValue.php | 6 ++++-- src/Expression/RangeValueInterface.php | 20 ++++++++++++++++++++ src/Expression/TsRangeValue.php | 6 ++++-- src/Expression/TsTzRangeValue.php | 6 ++++-- 9 files changed, 52 insertions(+), 17 deletions(-) create mode 100644 src/Expression/RangeValueInterface.php diff --git a/src/Column/AbstractMultiRangeColumn.php b/src/Column/AbstractMultiRangeColumn.php index 6125d3142..bfb71b2fc 100644 --- a/src/Column/AbstractMultiRangeColumn.php +++ b/src/Column/AbstractMultiRangeColumn.php @@ -7,6 +7,7 @@ use Yiisoft\Db\Exception\NotSupportedException; use Yiisoft\Db\Expression\ExpressionInterface; use Yiisoft\Db\Pgsql\Expression\MultiRangeValue; +use Yiisoft\Db\Pgsql\Expression\RangeValueInterface; use Yiisoft\Db\Schema\Column\AbstractColumn; use Yiisoft\Db\Schema\Column\ColumnInterface; @@ -15,7 +16,7 @@ use function is_string; /** - * @template T of ExpressionInterface + * @template T of RangeValueInterface */ abstract class AbstractMultiRangeColumn extends AbstractColumn { @@ -53,7 +54,7 @@ public function dbTypecast(mixed $value): mixed /** * @inheritDoc * - * @return ?ExpressionInterface[] + * @return ?RangeValueInterface[] * * @psalm-return ?T[] */ diff --git a/src/Column/AbstractRangeColumn.php b/src/Column/AbstractRangeColumn.php index 1c4a3fa8e..bcfa4bc4f 100644 --- a/src/Column/AbstractRangeColumn.php +++ b/src/Column/AbstractRangeColumn.php @@ -7,6 +7,7 @@ use InvalidArgumentException; use Yiisoft\Db\Exception\NotSupportedException; use Yiisoft\Db\Expression\ExpressionInterface; +use Yiisoft\Db\Pgsql\Expression\RangeValueInterface; use Yiisoft\Db\Schema\Column\AbstractColumn; use Yiisoft\Db\Schema\Column\ColumnInterface; @@ -16,7 +17,7 @@ use function sprintf; /** - * @template T of ExpressionInterface + * @template T of RangeValueInterface */ abstract class AbstractRangeColumn extends AbstractColumn { @@ -56,7 +57,7 @@ public function dbTypecast(mixed $value): mixed /** * @inheritDoc * - * @return ?ExpressionInterface + * @return ?RangeValueInterface * * @psalm-return ?T */ @@ -88,6 +89,8 @@ abstract protected function getBoundColumn(): ColumnInterface; /** * @throws NotSupportedException * + * @return RangeValueInterface + * * @psalm-return T */ abstract protected function createRangeValue( diff --git a/src/Expression/DateRangeValue.php b/src/Expression/DateRangeValue.php index 69da6f98f..f5c7e50d6 100644 --- a/src/Expression/DateRangeValue.php +++ b/src/Expression/DateRangeValue.php @@ -5,9 +5,11 @@ namespace Yiisoft\Db\Pgsql\Expression; use DateTimeImmutable; -use Yiisoft\Db\Expression\ExpressionInterface; -final class DateRangeValue implements ExpressionInterface +/** + * @implements RangeValueInterface + */ +final class DateRangeValue implements RangeValueInterface { public function __construct( public readonly ?DateTimeImmutable $lower = null, diff --git a/src/Expression/Int4RangeValue.php b/src/Expression/Int4RangeValue.php index 755c64514..4ca7e9f4e 100644 --- a/src/Expression/Int4RangeValue.php +++ b/src/Expression/Int4RangeValue.php @@ -4,9 +4,10 @@ namespace Yiisoft\Db\Pgsql\Expression; -use Yiisoft\Db\Expression\ExpressionInterface; - -final class Int4RangeValue implements ExpressionInterface +/** + * @implements RangeValueInterface + */ +final class Int4RangeValue implements RangeValueInterface { public function __construct( public readonly ?int $lower = null, diff --git a/src/Expression/Int8RangeValue.php b/src/Expression/Int8RangeValue.php index b5ec48b36..a4202f628 100644 --- a/src/Expression/Int8RangeValue.php +++ b/src/Expression/Int8RangeValue.php @@ -4,13 +4,15 @@ namespace Yiisoft\Db\Pgsql\Expression; -use Yiisoft\Db\Expression\ExpressionInterface; use InvalidArgumentException; use const PHP_INT_MAX; use const PHP_INT_MIN; -final class Int8RangeValue implements ExpressionInterface +/** + * @implements RangeValueInterface + */ +final class Int8RangeValue implements RangeValueInterface { public function __construct( public readonly int|string|null $lower = null, diff --git a/src/Expression/NumRangeValue.php b/src/Expression/NumRangeValue.php index 25e44bd1c..7c382a8f9 100644 --- a/src/Expression/NumRangeValue.php +++ b/src/Expression/NumRangeValue.php @@ -4,10 +4,12 @@ namespace Yiisoft\Db\Pgsql\Expression; -use Yiisoft\Db\Expression\ExpressionInterface; use RuntimeException; -final class NumRangeValue implements ExpressionInterface +/** + * @implements RangeValueInterface + */ +final class NumRangeValue implements RangeValueInterface { public function __construct( public readonly int|float|null $lower = null, diff --git a/src/Expression/RangeValueInterface.php b/src/Expression/RangeValueInterface.php new file mode 100644 index 000000000..4be955fdf --- /dev/null +++ b/src/Expression/RangeValueInterface.php @@ -0,0 +1,20 @@ + + */ +final class TsRangeValue implements RangeValueInterface { public function __construct( public readonly ?DateTimeImmutable $lower = null, diff --git a/src/Expression/TsTzRangeValue.php b/src/Expression/TsTzRangeValue.php index be9c85cf3..df77830ce 100644 --- a/src/Expression/TsTzRangeValue.php +++ b/src/Expression/TsTzRangeValue.php @@ -5,9 +5,11 @@ namespace Yiisoft\Db\Pgsql\Expression; use DateTimeImmutable; -use Yiisoft\Db\Expression\ExpressionInterface; -final class TsTzRangeValue implements ExpressionInterface +/** + * @implements RangeValueInterface + */ +final class TsTzRangeValue implements RangeValueInterface { public function __construct( public readonly ?DateTimeImmutable $lower = null, From 3eecd75b6730519f75d7e3e4c30398491aa5b6e9 Mon Sep 17 00:00:00 2001 From: Tigrov Date: Mon, 15 Jun 2026 21:23:52 +0700 Subject: [PATCH 4/5] Improve --- src/Expression/Int8RangeValue.php | 10 +++++++--- src/Expression/RangeValueInterface.php | 4 ++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Expression/Int8RangeValue.php b/src/Expression/Int8RangeValue.php index a4202f628..b638d85a4 100644 --- a/src/Expression/Int8RangeValue.php +++ b/src/Expression/Int8RangeValue.php @@ -4,7 +4,7 @@ namespace Yiisoft\Db\Pgsql\Expression; -use InvalidArgumentException; +use RuntimeException; use const PHP_INT_MAX; use const PHP_INT_MIN; @@ -28,7 +28,9 @@ public function getBounds(): array : ( PHP_INT_MIN <= $this->lower && $this->lower < PHP_INT_MAX ? (int) $this->lower + 1 - : throw new InvalidArgumentException('Lower bound cannot be determined from the excluded value of a bigint range.') + : throw new RuntimeException( + 'Lower bound cannot be determined from the excluded value of a bigint range.' + ) ); $upper = $this->upper === null || $this->includeUpper @@ -36,7 +38,9 @@ public function getBounds(): array : ( PHP_INT_MIN < $this->upper && $this->upper <= PHP_INT_MAX ? (int) $this->upper - 1 - : throw new InvalidArgumentException('Upper bound cannot be determined from the excluded value of a bigint range.') + : throw new RuntimeException( + 'Upper bound cannot be determined from the excluded value of a bigint range.' + ) ); return [$lower, $upper]; diff --git a/src/Expression/RangeValueInterface.php b/src/Expression/RangeValueInterface.php index 4be955fdf..e05e13196 100644 --- a/src/Expression/RangeValueInterface.php +++ b/src/Expression/RangeValueInterface.php @@ -5,8 +5,12 @@ namespace Yiisoft\Db\Pgsql\Expression; use Yiisoft\Db\Expression\ExpressionInterface; +use Yiisoft\Db\Pgsql\Column\AbstractMultiRangeColumn; +use Yiisoft\Db\Pgsql\Column\AbstractRangeColumn; /** + * Represents a range value of {@see AbstractRangeColumn} and {@see AbstractMultiRangeColumn} column types. + * * @template T */ interface RangeValueInterface extends ExpressionInterface From 077bf732a87bf6d4bce8c9f28b0aa2adc6e0c40e Mon Sep 17 00:00:00 2001 From: Tigrov <8563175+Tigrov@users.noreply.github.com> Date: Mon, 15 Jun 2026 14:25:06 +0000 Subject: [PATCH 5/5] Apply PHP CS Fixer and Rector changes (CI) --- src/Expression/Int8RangeValue.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Expression/Int8RangeValue.php b/src/Expression/Int8RangeValue.php index b638d85a4..5cc50e9b9 100644 --- a/src/Expression/Int8RangeValue.php +++ b/src/Expression/Int8RangeValue.php @@ -29,7 +29,7 @@ public function getBounds(): array PHP_INT_MIN <= $this->lower && $this->lower < PHP_INT_MAX ? (int) $this->lower + 1 : throw new RuntimeException( - 'Lower bound cannot be determined from the excluded value of a bigint range.' + 'Lower bound cannot be determined from the excluded value of a bigint range.', ) ); @@ -39,7 +39,7 @@ public function getBounds(): array PHP_INT_MIN < $this->upper && $this->upper <= PHP_INT_MAX ? (int) $this->upper - 1 : throw new RuntimeException( - 'Upper bound cannot be determined from the excluded value of a bigint range.' + 'Upper bound cannot be determined from the excluded value of a bigint range.', ) );