diff --git a/src/Prime/Storage/Filter/Criteria/OrderByCriteria.php b/src/Prime/Storage/Filter/Criteria/OrderByCriteria.php index 2c62629b..b3be16ba 100644 --- a/src/Prime/Storage/Filter/Criteria/OrderByCriteria.php +++ b/src/Prime/Storage/Filter/Criteria/OrderByCriteria.php @@ -98,12 +98,16 @@ final class OrderByCriteria implements CriteriaInterface $stampB = $second->get($field); if (!$stampA instanceof OrderableStampInterface || !$stampB instanceof OrderableStampInterface) { - return 0; + continue; } - return self::ASC === $ordering + $comparison = self::ASC === $ordering ? $stampA->compare($stampB) : $stampB->compare($stampA); + + if (0 !== $comparison) { + return $comparison; + } } return 0; diff --git a/tests/Prime/Storage/Filter/Criteria/OrderByCriteriaTest.php b/tests/Prime/Storage/Filter/Criteria/OrderByCriteriaTest.php new file mode 100644 index 00000000..e153b448 --- /dev/null +++ b/tests/Prime/Storage/Filter/Criteria/OrderByCriteriaTest.php @@ -0,0 +1,100 @@ +createEnvelope('a', 1, new \DateTimeImmutable('2024-01-03')), + $this->createEnvelope('b', 1, new \DateTimeImmutable('2024-01-01')), + $this->createEnvelope('c', 1, new \DateTimeImmutable('2024-01-02')), + $this->createEnvelope('d', 2, new \DateTimeImmutable('2024-01-01')), + ]; + + $criteria = new OrderByCriteria([ + 'priority' => OrderByCriteria::ASC, + 'created_at' => OrderByCriteria::DESC, + ]); + + $result = $criteria->apply($envelopes); + + $ids = array_map(fn (Envelope $e) => $e->getTitle(), $result); + + $this->assertSame(['a', 'c', 'b', 'd'], $ids); + } + + public function testSingleFieldSorting(): void + { + $envelopes = [ + $this->createEnvelope('a', 3), + $this->createEnvelope('b', 1), + $this->createEnvelope('c', 2), + ]; + + $criteria = new OrderByCriteria('priority'); + + $result = $criteria->apply($envelopes); + + $ids = array_map(fn (Envelope $e) => $e->getTitle(), $result); + + $this->assertSame(['b', 'c', 'a'], $ids); + } + + public function testDescendingOrder(): void + { + $envelopes = [ + $this->createEnvelope('a', 1), + $this->createEnvelope('b', 3), + $this->createEnvelope('c', 2), + ]; + + $criteria = new OrderByCriteria(['priority' => OrderByCriteria::DESC]); + + $result = $criteria->apply($envelopes); + + $ids = array_map(fn (Envelope $e) => $e->getTitle(), $result); + + $this->assertSame(['b', 'c', 'a'], $ids); + } + + public function testInvalidDirection(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid ordering direction'); + + new OrderByCriteria(['priority' => 'INVALID']); + } + + public function testInvalidField(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('is not a valid class-string'); + + new OrderByCriteria(['NonExistentStamp' => OrderByCriteria::ASC]); + } + + private function createEnvelope(string $id, int $priority, ?\DateTimeImmutable $createdAt = null): Envelope + { + $notification = new Notification(); + $notification->setTitle($id); + + $stamps = [new PriorityStamp($priority)]; + + if (null !== $createdAt) { + $stamps[] = new CreatedAtStamp($createdAt); + } + + return new Envelope($notification, $stamps); + } +}