Skip to content

Commit c8b5b7f

Browse files
committed
feat(database): add skip-take pagination support
1 parent fda0658 commit c8b5b7f

File tree

3 files changed

+69
-4
lines changed

3 files changed

+69
-4
lines changed

packages/database/src/Builder/ModelInspector.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ final class ModelInspector
3131

3232
private(set) object|string $instance;
3333

34-
public function __construct(object|string $model)
35-
{
34+
public function __construct(
35+
private(set) object|string $model,
36+
) {
3637
if ($model instanceof HasMany) {
3738
$model = $model->property->getIterableType()->asClass();
3839
$this->reflector = $model;

packages/database/src/Builder/QueryBuilders/SelectQueryBuilder.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
use Tempest\Database\QueryStatements\SelectStatement;
2121
use Tempest\Support\Arr\ImmutableArray;
2222
use Tempest\Support\Conditions\HasConditions;
23+
use Tempest\Support\Paginator\PaginatedData;
24+
use Tempest\Support\Paginator\Paginator;
2325

2426
use function Tempest\Database\model;
2527
use function Tempest\map;
@@ -78,6 +80,23 @@ public function first(mixed ...$bindings): mixed
7880
return $result[array_key_first($result)];
7981
}
8082

83+
/** @return PaginatedData<TModelClass> */
84+
public function paginate(int $itemsPerPage = 20, int $currentPage = 1, int $maxLinks = 10): PaginatedData
85+
{
86+
$total = new CountQueryBuilder($this->model->model)->execute();
87+
88+
$paginator = new Paginator(
89+
totalItems: $total,
90+
itemsPerPage: $itemsPerPage,
91+
currentPage: $currentPage,
92+
maxLinks: $maxLinks,
93+
);
94+
95+
return $paginator->paginateWith(
96+
callback: fn (int $limit, int $offset) => $this->limit($limit)->offset($offset)->all(),
97+
);
98+
}
99+
81100
/** @return TModelClass|null */
82101
public function get(Id $id): mixed
83102
{

tests/Integration/Database/Builder/SelectQueryBuilderTest.php

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
namespace Tests\Tempest\Integration\Database\Builder;
66

77
use Tempest\Database\Builder\QueryBuilders\SelectQueryBuilder;
8-
use Tempest\Database\Config\SQLiteConfig;
98
use Tempest\Database\Migrations\CreateMigrationsTable;
10-
use Tempest\Database\Migrations\MigrationManager;
119
use Tests\Tempest\Fixtures\Migrations\CreateAuthorTable;
1210
use Tests\Tempest\Fixtures\Migrations\CreateBookTable;
1311
use Tests\Tempest\Fixtures\Migrations\CreateChapterTable;
@@ -17,6 +15,7 @@
1715
use Tests\Tempest\Fixtures\Modules\Books\Models\Author;
1816
use Tests\Tempest\Fixtures\Modules\Books\Models\AuthorType;
1917
use Tests\Tempest\Fixtures\Modules\Books\Models\Book;
18+
use Tests\Tempest\Fixtures\Modules\Books\Models\Chapter;
2019
use Tests\Tempest\Integration\FrameworkIntegrationTestCase;
2120

2221
use function Tempest\Database\query;
@@ -441,6 +440,52 @@ public function test_having(): void
441440
$this->assertSameWithoutBackticks($expected, $sql);
442441
}
443442

443+
public function test_paginate(): void
444+
{
445+
$this->seed();
446+
447+
$page1 = query(Chapter::class)
448+
->select()
449+
->paginate(itemsPerPage: 2);
450+
451+
$this->assertSame(1, $page1->currentPage);
452+
$this->assertSame(7, $page1->totalPages);
453+
$this->assertSame(13, $page1->totalItems);
454+
$this->assertSame(2, $page1->itemsPerPage);
455+
$this->assertSame(0, $page1->offset);
456+
$this->assertSame(2, $page1->limit);
457+
$this->assertSame(2, $page1->nextPage);
458+
$this->assertSame(null, $page1->previousPage);
459+
$this->assertSame(true, $page1->hasNext);
460+
$this->assertSame(false, $page1->hasPrevious);
461+
462+
$this->assertSame('LOTR 1.1', $page1->data[0]->title);
463+
$this->assertSame('LOTR 1.2', $page1->data[1]->title);
464+
465+
$page3 = query(Chapter::class)
466+
->select()
467+
->paginate(itemsPerPage: 2, currentPage: 3);
468+
469+
$this->assertSame(3, $page3->currentPage);
470+
$this->assertSame('LOTR 2.2', $page3->data[0]->title);
471+
$this->assertSame('LOTR 2.3', $page3->data[1]->title);
472+
473+
$page7 = query(Chapter::class)
474+
->select()
475+
->paginate(itemsPerPage: 2, currentPage: 7);
476+
477+
$this->assertSame(7, $page7->currentPage);
478+
$this->assertSame('Timeline Taxi Chapter 4', $page7->data[0]->title);
479+
480+
// capped to last page, so this will be page 7
481+
$page10 = query(Chapter::class)
482+
->select()
483+
->paginate(itemsPerPage: 2, currentPage: 10);
484+
485+
$this->assertSame(7, $page10->currentPage);
486+
$this->assertSame('Timeline Taxi Chapter 4', $page10->data[0]->title);
487+
}
488+
444489
private function seed(): void
445490
{
446491
$this->migrate(

0 commit comments

Comments
 (0)