diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/DateTimeStepRangesGenerator.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/DateTimeStepRangesGenerator.php index f7e5f25656..d68036c815 100644 --- a/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/DateTimeStepRangesGenerator.php +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/DateTimeStepRangesGenerator.php @@ -26,7 +26,6 @@ final class DateTimeStepRangesGenerator implements RangesGeneratorInterface private bool $isRightOpen = true; - public function __construct(DateTimeInterface $start, DateTimeInterface $end) { $this->start = $start; @@ -97,6 +96,12 @@ public function setRightOpen(bool $isRightOpen): self */ public function generate(): array { + if ($this->start == $this->end && $this->isLeftOpen && $this->isRightOpen) { + return [ + new Range(Range::INF, Range::INF), + ]; + } + $ranges = []; if ($this->isLeftOpen) { @@ -109,7 +114,7 @@ public function generate(): array $current = DateTimeImmutable::createFromMutable($current); } - while ($current <= $this->end) { + while ($current < $this->end) { $next = $current->add($this->step); $ranges[] = Range::ofDateTime($current, $next); $current = $next; diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/FloatStepRangesGenerator.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/FloatStepRangesGenerator.php index 24a8e72c66..43fdec93a7 100644 --- a/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/FloatStepRangesGenerator.php +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/FloatStepRangesGenerator.php @@ -69,9 +69,11 @@ public function isLeftOpen(): bool return $this->isLeftOpen; } - public function setLeftOpen(bool $isLeftOpen): void + public function setLeftOpen(bool $isLeftOpen): self { $this->isLeftOpen = $isLeftOpen; + + return $this; } public function isRightOpen(): bool @@ -91,6 +93,12 @@ public function setRightOpen(bool $isRightOpen): self */ public function generate(): array { + if ($this->start === $this->end && $this->isLeftOpen && $this->isRightOpen) { + return [ + new Range(Range::INF, Range::INF), + ]; + } + $ranges = []; if ($this->isLeftOpen) { diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/IntegerStepRangesGenerator.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/IntegerStepRangesGenerator.php index 8322bf033f..015ec765df 100644 --- a/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/IntegerStepRangesGenerator.php +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/IntegerStepRangesGenerator.php @@ -8,6 +8,7 @@ namespace Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Ranges; +use Generator; use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range; final class IntegerStepRangesGenerator implements RangesGeneratorInterface @@ -69,9 +70,11 @@ public function isLeftOpen(): bool return $this->isLeftOpen; } - public function setLeftOpen(bool $isLeftOpen): void + public function setLeftOpen(bool $isLeftOpen): self { $this->isLeftOpen = $isLeftOpen; + + return $this; } public function isRightOpen(): bool @@ -89,8 +92,14 @@ public function setRightOpen(bool $isRightOpen): self /** * @return \Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range[] */ - public function generate(): \Generator + public function generate(): Generator { + if ($this->start === $this->end && $this->isLeftOpen && $this->isRightOpen) { + yield new Range(Range::INF, Range::INF); + + return; + } + if ($this->isLeftOpen) { yield Range::ofInt(Range::INF, $this->start); } diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/RangesGeneratorInterface.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/RangesGeneratorInterface.php index 4bc05f7c0c..e059013ca6 100644 --- a/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/RangesGeneratorInterface.php +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/RangesGeneratorInterface.php @@ -1,4 +1,9 @@ createRange(Range::INF, '01-01-2023'), + $this->createRange('01-01-2023', '02-01-2023'), + $this->createRange('02-01-2023', '03-01-2023'), + $this->createRange('03-01-2023', Range::INF), + ], + new DateTimeStepRangesGenerator( + new DateTimeImmutable('01-01-2023 00:00:00'), + new DateTimeImmutable('03-01-2023 00:00:00') + ) + ); + } + + public function testGenerateCloseRangesSequence(): void + { + $generator = new DateTimeStepRangesGenerator( + new DateTimeImmutable('01-01-2023 00:00:00'), + new DateTimeImmutable('03-01-2023 00:00:00') + ); + $generator->setLeftOpen(false); + $generator->setRightOpen(false); + + self::assertGeneratorResults( + [ + $this->createRange('01-01-2023', '02-01-2023'), + $this->createRange('02-01-2023', '03-01-2023'), + ], + $generator + ); + } + + public function testGenerateRangesWithCustomStep(): void + { + $generator = new DateTimeStepRangesGenerator( + new DateTimeImmutable('01-01-2023 00:00:00'), + new DateTimeImmutable('05-01-2023 00:00:00') + ); + $generator->setStep(new DateInterval('P2D')); + + self::assertGeneratorResults( + [ + $this->createRange(Range::INF, '01-01-2023'), + $this->createRange('01-01-2023', '03-01-2023'), + $this->createRange('03-01-2023', '05-01-2023'), + $this->createRange('05-01-2023', Range::INF), + ], + $generator + ); + } + + public function testGenerateInfRangesSequence(): void + { + $generator = new DateTimeStepRangesGenerator( + new DateTimeImmutable('01-01-1970 00:00:00'), + new DateTimeImmutable('01-01-1970 00:00:00'), + ); + + self::assertGeneratorResults( + [ + Range::ofDateTime(Range::INF, Range::INF), + ], + $generator + ); + } + + public function testGenerateEmptyRangesSequence(): void + { + $generator = new DateTimeStepRangesGenerator( + new DateTimeImmutable('01-01-1970 00:00:00'), + new DateTimeImmutable('01-01-1970 00:00:00'), + ); + $generator->setLeftOpen(false); + $generator->setRightOpen(false); + + self::assertGeneratorResults([], $generator); + } + + private function createRange(?string $start, ?string $end): Range + { + return Range::ofDateTime( + $start !== null ? new DateTimeImmutable($start . ' 00:00:00') : null, + $end !== null ? new DateTimeImmutable($end . ' 00:00:00') : null + ); + } + + /** + * @param \Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range[] $expectedResult + */ + private static function assertGeneratorResults(array $expectedResult, DateTimeStepRangesGenerator $generator): void + { + self::assertEquals($expectedResult, $generator->generate()); + } +} diff --git a/tests/integration/Core/Repository/Values/Content/Query/Aggregation/Ranges/FloatStepRangesGeneratorTest.php b/tests/integration/Core/Repository/Values/Content/Query/Aggregation/Ranges/FloatStepRangesGeneratorTest.php new file mode 100644 index 0000000000..f41391acab --- /dev/null +++ b/tests/integration/Core/Repository/Values/Content/Query/Aggregation/Ranges/FloatStepRangesGeneratorTest.php @@ -0,0 +1,91 @@ +setLeftOpen(false); + $generator->setRightOpen(false); + + self::assertGeneratorResults( + [ + Range::ofFloat(1.0, 2.0), + Range::ofFloat(2.0, 3.0), + ], + $generator + ); + } + + public function testGenerateRangesWithCustomStep(): void + { + $generator = new FloatStepRangesGenerator(1.0, 10.0); + $generator->setStep(2.0); + + self::assertGeneratorResults( + [ + Range::ofFloat(Range::INF, 1.0), + Range::ofFloat(1.0, 3.0), + Range::ofFloat(3.0, 5.0), + Range::ofFloat(5.0, 7.0), + Range::ofFloat(7.0, 9.0), + Range::ofFloat(10.0, Range::INF), + ], + $generator + ); + } + + public function testGenerateInfRangesSequence(): void + { + $generator = new FloatStepRangesGenerator(0.0, 0.0); + + self::assertGeneratorResults( + [ + Range::ofFloat(Range::INF, Range::INF), + ], + $generator + ); + } + + public function testGenerateEmptyRangesSequence(): void + { + $generator = new FloatStepRangesGenerator(0.0, 0.0); + $generator->setLeftOpen(false); + $generator->setRightOpen(false); + + self::assertGeneratorResults([], $generator); + } + + /** + * @param \Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range[] $expectedResult + */ + private static function assertGeneratorResults(array $expectedResult, FloatStepRangesGenerator $generator): void + { + self::assertEquals($expectedResult, $generator->generate()); + } +} diff --git a/tests/integration/Core/Repository/Values/Content/Query/Aggregation/Ranges/IntegerStepRangesGeneratorTest.php b/tests/integration/Core/Repository/Values/Content/Query/Aggregation/Ranges/IntegerStepRangesGeneratorTest.php new file mode 100644 index 0000000000..272e2e095b --- /dev/null +++ b/tests/integration/Core/Repository/Values/Content/Query/Aggregation/Ranges/IntegerStepRangesGeneratorTest.php @@ -0,0 +1,94 @@ +setLeftOpen(false); + $generator->setRightOpen(false); + + self::assertGeneratorResults( + [ + Range::ofInt(1, 2), + Range::ofInt(2, 3), + ], + $generator + ); + } + + public function testGenerateRangesWithCustomStep(): void + { + $generator = new IntegerStepRangesGenerator(1, 10); + $generator->setStep(2); + + self::assertGeneratorResults( + [ + Range::ofInt(Range::INF, 1), + Range::ofInt(1, 3), + Range::ofInt(3, 5), + Range::ofInt(5, 7), + Range::ofInt(7, 9), + Range::ofInt(10, Range::INF), + ], + $generator + ); + } + + public function testGenerateInfRangesSequence(): void + { + $generator = new IntegerStepRangesGenerator(0, 0); + + self::assertGeneratorResults( + [ + Range::ofInt(Range::INF, Range::INF), + ], + $generator + ); + } + + public function testGenerateEmptyRangesSequence(): void + { + $generator = new IntegerStepRangesGenerator(0, 0); + $generator->setLeftOpen(false); + $generator->setRightOpen(false); + + self::assertGeneratorResults([], $generator); + } + + /** + * @param \Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range[] $expectedResult + */ + private static function assertGeneratorResults(array $expectedResult, IntegerStepRangesGenerator $generator): void + { + self::assertEquals( + $expectedResult, + iterator_to_array($generator->generate()) + ); + } +}