diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/DateMetadataRangeAggregation.php b/src/contracts/Repository/Values/Content/Query/Aggregation/DateMetadataRangeAggregation.php index 33d54bf039..2dfa08ad53 100644 --- a/src/contracts/Repository/Values/Content/Query/Aggregation/DateMetadataRangeAggregation.php +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/DateMetadataRangeAggregation.php @@ -8,6 +8,9 @@ namespace Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Ranges\RangesGeneratorInterface; +use Traversable; + final class DateMetadataRangeAggregation extends AbstractRangeAggregation { public const MODIFIED = 'modified'; @@ -27,6 +30,19 @@ public function getType(): string { return $this->type; } + + public static function fromGenerator( + string $name, + string $type, + RangesGeneratorInterface $generator + ): self { + $ranges = $generator->generate(); + if ($ranges instanceof Traversable) { + $ranges = iterator_to_array($ranges); + } + + return new self($name, $type, $ranges); + } } class_alias(DateMetadataRangeAggregation::class, 'eZ\Publish\API\Repository\Values\Content\Query\Aggregation\DateMetadataRangeAggregation'); diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Field/DateRangeAggregation.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Field/DateRangeAggregation.php index 0be15c9413..8b225caf25 100644 --- a/src/contracts/Repository/Values/Content/Query/Aggregation/Field/DateRangeAggregation.php +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Field/DateRangeAggregation.php @@ -8,8 +8,24 @@ namespace Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Field; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Ranges\RangesGeneratorInterface; +use Traversable; + final class DateRangeAggregation extends AbstractFieldRangeAggregation { + public static function fromGenerator( + string $name, + string $contentTypeIdentifier, + string $fieldDefinitionIdentifier, + RangesGeneratorInterface $generator + ): self { + $ranges = $generator->generate(); + if ($ranges instanceof Traversable) { + $ranges = iterator_to_array($ranges); + } + + return new self($name, $contentTypeIdentifier, $fieldDefinitionIdentifier, $ranges); + } } class_alias(DateRangeAggregation::class, 'eZ\Publish\API\Repository\Values\Content\Query\Aggregation\Field\DateRangeAggregation'); diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Field/DateTimeRangeAggregation.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Field/DateTimeRangeAggregation.php index a6a155b62b..3963444ecc 100644 --- a/src/contracts/Repository/Values/Content/Query/Aggregation/Field/DateTimeRangeAggregation.php +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Field/DateTimeRangeAggregation.php @@ -8,8 +8,24 @@ namespace Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Field; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Ranges\RangesGeneratorInterface; +use Traversable; + final class DateTimeRangeAggregation extends AbstractFieldRangeAggregation { + public static function fromGenerator( + string $name, + string $contentTypeIdentifier, + string $fieldDefinitionIdentifier, + RangesGeneratorInterface $generator + ): self { + $ranges = $generator->generate(); + if ($ranges instanceof Traversable) { + $ranges = iterator_to_array($ranges); + } + + return new self($name, $contentTypeIdentifier, $fieldDefinitionIdentifier, $ranges); + } } class_alias(DateTimeRangeAggregation::class, 'eZ\Publish\API\Repository\Values\Content\Query\Aggregation\Field\DateTimeRangeAggregation'); diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Field/FloatRangeAggregation.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Field/FloatRangeAggregation.php index 9c2ad230c2..188a15396f 100644 --- a/src/contracts/Repository/Values/Content/Query/Aggregation/Field/FloatRangeAggregation.php +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Field/FloatRangeAggregation.php @@ -8,8 +8,24 @@ namespace Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Field; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Ranges\RangesGeneratorInterface; +use Traversable; + final class FloatRangeAggregation extends AbstractFieldRangeAggregation { + public static function fromGenerator( + string $name, + string $contentTypeIdentifier, + string $fieldDefinitionIdentifier, + RangesGeneratorInterface $generator + ): self { + $ranges = $generator->generate(); + if ($ranges instanceof Traversable) { + $ranges = iterator_to_array($ranges); + } + + return new self($name, $contentTypeIdentifier, $fieldDefinitionIdentifier, $ranges); + } } class_alias(FloatRangeAggregation::class, 'eZ\Publish\API\Repository\Values\Content\Query\Aggregation\Field\FloatRangeAggregation'); diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Field/IntegerRangeAggregation.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Field/IntegerRangeAggregation.php index 3fdde15481..e79fe6dd28 100644 --- a/src/contracts/Repository/Values/Content/Query/Aggregation/Field/IntegerRangeAggregation.php +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Field/IntegerRangeAggregation.php @@ -8,8 +8,24 @@ namespace Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Field; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Ranges\RangesGeneratorInterface; +use Traversable; + final class IntegerRangeAggregation extends AbstractFieldRangeAggregation { + public static function fromGenerator( + string $name, + string $contentTypeIdentifier, + string $fieldDefinitionIdentifier, + RangesGeneratorInterface $generator + ): self { + $ranges = $generator->generate(); + if ($ranges instanceof Traversable) { + $ranges = iterator_to_array($ranges); + } + + return new static($name, $contentTypeIdentifier, $fieldDefinitionIdentifier, $ranges); + } } class_alias(IntegerRangeAggregation::class, 'eZ\Publish\API\Repository\Values\Content\Query\Aggregation\Field\IntegerRangeAggregation'); diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Field/TimeRangeAggregation.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Field/TimeRangeAggregation.php index 7b2d5c9c7c..30907ec4b1 100644 --- a/src/contracts/Repository/Values/Content/Query/Aggregation/Field/TimeRangeAggregation.php +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Field/TimeRangeAggregation.php @@ -8,8 +8,24 @@ namespace Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Field; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Ranges\RangesGeneratorInterface; +use Traversable; + final class TimeRangeAggregation extends AbstractFieldRangeAggregation { + public static function fromGenerator( + string $name, + string $contentTypeIdentifier, + string $fieldDefinitionIdentifier, + RangesGeneratorInterface $generator + ): self { + $ranges = $generator->generate(); + if ($ranges instanceof Traversable) { + $ranges = iterator_to_array($ranges); + } + + return new self($name, $contentTypeIdentifier, $fieldDefinitionIdentifier, $ranges); + } } class_alias(TimeRangeAggregation::class, 'eZ\Publish\API\Repository\Values\Content\Query\Aggregation\Field\TimeRangeAggregation'); diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Range.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Range.php index b5ec1d20b2..aea16b7214 100644 --- a/src/contracts/Repository/Values/Content/Query/Aggregation/Range.php +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Range.php @@ -13,6 +13,8 @@ final class Range extends ValueObject { + public const INF = null; + /** * Beginning of the range (included). * @@ -27,12 +29,15 @@ final class Range extends ValueObject */ private $to; - public function __construct($from, $to) + private ?string $label; + + public function __construct($from, $to, ?string $label = null) { parent::__construct(); $this->from = $from; $this->to = $to; + $this->label = $label; } public function getFrom() @@ -45,8 +50,27 @@ public function getTo() return $this->to; } + public function getLabel(): ?string + { + return $this->label; + } + + public function setLabel(?string $label): void + { + $this->label = $label; + } + public function __toString(): string { + if ($this->label !== null) { + return sprintf( + '%s:[%s;%s)', + $this->label, + $this->getRangeValueAsString($this->from), + $this->getRangeValueAsString($this->to) + ); + } + return sprintf( '[%s;%s)', $this->getRangeValueAsString($this->from), @@ -54,6 +78,11 @@ public function __toString(): string ); } + public function equalsTo(Range $value): bool + { + return $this->from == $value->from && $this->to == $value->to; + } + private function getRangeValueAsString($value): string { if ($value === null) { diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/DateTimeStepRangesGenerator.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/DateTimeStepRangesGenerator.php new file mode 100644 index 0000000000..d68036c815 --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/DateTimeStepRangesGenerator.php @@ -0,0 +1,129 @@ +start = $start; + $this->end = $end; + $this->step = new DateInterval('P1D'); + } + + public function getStart(): DateTimeInterface + { + return $this->start; + } + + public function setStart(DateTimeInterface $start): self + { + $this->start = $start; + + return $this; + } + + public function getEnd(): DateTimeInterface + { + return $this->end; + } + + public function setEnd(DateTimeInterface $end): self + { + $this->end = $end; + + return $this; + } + + public function getStep(): DateInterval + { + return $this->step; + } + + public function setStep(DateInterval $step): self + { + $this->step = $step; + + return $this; + } + + public function isLeftOpen(): bool + { + return $this->isLeftOpen; + } + + public function setLeftOpen(bool $isLeftOpen): void + { + $this->isLeftOpen = $isLeftOpen; + } + + public function isRightOpen(): bool + { + return $this->isRightOpen; + } + + public function setRightOpen(bool $isRightOpen): self + { + $this->isRightOpen = $isRightOpen; + + return $this; + } + + /** + * @return \Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range[] + */ + public function generate(): array + { + if ($this->start == $this->end && $this->isLeftOpen && $this->isRightOpen) { + return [ + new Range(Range::INF, Range::INF), + ]; + } + + $ranges = []; + + if ($this->isLeftOpen) { + $ranges[] = Range::ofDateTime(Range::INF, $this->start); + } + + /** @var \DateTimeImmutable $current */ + $current = $this->start; + if ($current instanceof DateTime) { + $current = DateTimeImmutable::createFromMutable($current); + } + + while ($current < $this->end) { + $next = $current->add($this->step); + $ranges[] = Range::ofDateTime($current, $next); + $current = $next; + } + + if ($this->isRightOpen) { + $ranges[] = Range::ofDateTime($this->end, Range::INF); + } + + return $ranges; + } +} diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/FloatStepRangesGenerator.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/FloatStepRangesGenerator.php new file mode 100644 index 0000000000..fd265d190d --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/FloatStepRangesGenerator.php @@ -0,0 +1,119 @@ +start = $start; + $this->end = $end; + } + + public function getStart(): float + { + return $this->start; + } + + public function setStart(float $start): self + { + $this->start = $start; + + return $this; + } + + public function getEnd(): float + { + return $this->end; + } + + public function setEnd(float $end): self + { + $this->end = $end; + + return $this; + } + + public function getStep(): float + { + return $this->step; + } + + public function setStep(float $step): self + { + $this->step = $step; + + return $this; + } + + public function isLeftOpen(): bool + { + return $this->isLeftOpen; + } + + public function setLeftOpen(bool $isLeftOpen): self + { + $this->isLeftOpen = $isLeftOpen; + + return $this; + } + + public function isRightOpen(): bool + { + return $this->isRightOpen; + } + + public function setRightOpen(bool $isRightOpen): self + { + $this->isRightOpen = $isRightOpen; + + return $this; + } + + /** + * @return \Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range[] + */ + public function generate(): array + { + if ($this->start === $this->end && $this->isLeftOpen && $this->isRightOpen) { + return [ + new Range(Range::INF, Range::INF), + ]; + } + + $ranges = []; + + if ($this->isLeftOpen) { + $ranges[] = Range::ofFloat(Range::INF, $this->start); + } + + $values = range($this->start, $this->end, $this->step); + for ($i = 1, $count = count($values); $i < $count; ++$i) { + $ranges[] = Range::ofFloat($values[$i - 1], $values[$i]); + } + + if ($this->isRightOpen) { + $ranges[] = Range::ofFloat($this->end, Range::INF); + } + + return $ranges; + } +} diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/IntegerStepRangesGenerator.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/IntegerStepRangesGenerator.php new file mode 100644 index 0000000000..154f172e53 --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/IntegerStepRangesGenerator.php @@ -0,0 +1,116 @@ +start = $start; + $this->end = $end; + } + + public function getStart(): int + { + return $this->start; + } + + public function setStart(int $start): self + { + $this->start = $start; + + return $this; + } + + public function getEnd(): int + { + return $this->end; + } + + public function setEnd(int $end): self + { + $this->end = $end; + + return $this; + } + + public function getStep(): int + { + return $this->step; + } + + public function setStep(int $step): self + { + $this->step = $step; + + return $this; + } + + public function isLeftOpen(): bool + { + return $this->isLeftOpen; + } + + public function setLeftOpen(bool $isLeftOpen): self + { + $this->isLeftOpen = $isLeftOpen; + + return $this; + } + + public function isRightOpen(): bool + { + return $this->isRightOpen; + } + + public function setRightOpen(bool $isRightOpen): self + { + $this->isRightOpen = $isRightOpen; + + return $this; + } + + /** + * @return \Generator<\Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range> + */ + 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); + } + + $values = range($this->start, $this->end, $this->step); + for ($i = 1, $count = count($values); $i < $count; ++$i) { + yield Range::ofInt($values[$i - 1], $values[$i]); + } + + if ($this->isRightOpen) { + yield Range::ofInt($this->end, Range::INF); + } + } +} diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/RangesGeneratorInterface.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/RangesGeneratorInterface.php new file mode 100644 index 0000000000..e059013ca6 --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/RangesGeneratorInterface.php @@ -0,0 +1,17 @@ +fieldName; } + + public static function fromGenerator( + string $name, + string $fieldName, + RangesGeneratorInterface $generator + ): self { + $ranges = $generator->generate(); + if ($ranges instanceof Traversable) { + $ranges = iterator_to_array($ranges); + } + + return new self($name, $fieldName, $ranges); + } } class_alias(RawRangeAggregation::class, 'eZ\Publish\API\Repository\Values\Content\Query\Aggregation\RawRangeAggregation'); diff --git a/src/contracts/Repository/Values/Content/Search/AggregationResult/RangeAggregationResult.php b/src/contracts/Repository/Values/Content/Search/AggregationResult/RangeAggregationResult.php index 52996d65eb..8f7d98908e 100644 --- a/src/contracts/Repository/Values/Content/Search/AggregationResult/RangeAggregationResult.php +++ b/src/contracts/Repository/Values/Content/Search/AggregationResult/RangeAggregationResult.php @@ -59,6 +59,18 @@ public function hasEntry(Range $key): bool return $this->getEntry($key) !== null; } + /** + * Return available keys (ranges). + * + * @return iterable<\Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range> + */ + public function getKeys(): iterable + { + foreach ($this->entries as $entry) { + yield $entry->getKey(); + } + } + public function count(): int { return count($this->entries); diff --git a/src/contracts/Repository/Values/Content/Search/AggregationResult/TermAggregationResult.php b/src/contracts/Repository/Values/Content/Search/AggregationResult/TermAggregationResult.php index 5eec15e660..cf2f0e4412 100644 --- a/src/contracts/Repository/Values/Content/Search/AggregationResult/TermAggregationResult.php +++ b/src/contracts/Repository/Values/Content/Search/AggregationResult/TermAggregationResult.php @@ -62,6 +62,18 @@ public function hasEntry($key): bool return $this->getEntry($key) !== null; } + /** + * Returns available keys (terms). + * + * @return iterable + */ + public function getKeys(): iterable + { + foreach ($this->entries as $entry) { + yield $entry->getKey(); + } + } + public function count(): int { return count($this->entries); diff --git a/tests/integration/Core/Repository/Values/Content/Query/Aggregation/Ranges/DateTimeStepRangesGeneratorTest.php b/tests/integration/Core/Repository/Values/Content/Query/Aggregation/Ranges/DateTimeStepRangesGeneratorTest.php new file mode 100644 index 0000000000..6c662f5483 --- /dev/null +++ b/tests/integration/Core/Repository/Values/Content/Query/Aggregation/Ranges/DateTimeStepRangesGeneratorTest.php @@ -0,0 +1,114 @@ +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()) + ); + } +} diff --git a/tests/lib/Repository/Values/Content/Query/Aggregation/RangeTest.php b/tests/lib/Repository/Values/Content/Query/Aggregation/RangeTest.php index afd4a73421..7cffc94f41 100644 --- a/tests/lib/Repository/Values/Content/Query/Aggregation/RangeTest.php +++ b/tests/lib/Repository/Values/Content/Query/Aggregation/RangeTest.php @@ -71,6 +71,69 @@ public function testOfDateTime(): void $this->assertEquals(new Range($a, $b), Range::ofDateTime($a, $b)); $this->assertEquals(new Range($a, null), Range::ofDateTime($a, null)); } + + /** + * @dataProvider dataProviderForEqualsTo + */ + public function testEqualsTo(Range $rangeA, Range $rangeB, bool $expectedResult): void + { + self::assertEquals($expectedResult, $rangeA->equalsTo($rangeB)); + self::assertEquals($expectedResult, $rangeB->equalsTo($rangeA)); + } + + /** + * @return iterable + */ + public function dataProviderForEqualsTo(): iterable + { + yield 'int (true)' => [ + Range::ofInt(1, 10), + Range::ofInt(1, 10), + true, + ]; + + yield 'int (false)' => [ + Range::ofInt(1, 10), + Range::ofInt(1, 100), + false, + ]; + + yield 'float (true)' => [ + Range::ofFloat(1.0, 10.0), + Range::ofFloat(1.0, 10.0), + true, + ]; + + yield 'float (false)' => [ + Range::ofFloat(1.0, 10.0), + Range::ofFloat(1.0, 100.0), + false, + ]; + + yield 'data & time (true)' => [ + Range::ofDateTime( + new DateTimeImmutable('2023-01-01 00:00:00'), + new DateTimeImmutable('2023-12-01 00:00:00') + ), + Range::ofDateTime( + new DateTimeImmutable('2023-01-01 00:00:00'), + new DateTimeImmutable('2023-12-01 00:00:00') + ), + true, + ]; + + yield 'data & time (false)' => [ + Range::ofDateTime( + new DateTimeImmutable('2023-01-01 00:00:00'), + new DateTimeImmutable('2023-12-01 00:00:00') + ), + Range::ofDateTime( + new DateTimeImmutable('2024-01-01 00:00:00'), + new DateTimeImmutable('2024-12-01 00:00:00') + ), + false, + ]; + } } class_alias(RangeTest::class, 'eZ\Publish\API\Repository\Tests\Values\Content\Query\Aggregation\RangeTest');