Skip to content

Commit

Permalink
feat(database): chunked results (#855)
Browse files Browse the repository at this point in the history
  • Loading branch information
brendt authored Dec 13, 2024
1 parent 61e7abb commit e332bbd
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 0 deletions.
36 changes: 36 additions & 0 deletions src/Tempest/Database/src/Builder/ModelQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Tempest\Database\Builder;

use Closure;
use Tempest\Database\DatabaseModel;
use Tempest\Database\Id;
use Tempest\Database\Query;
Expand All @@ -22,6 +23,8 @@ final class ModelQueryBuilder

private ?int $limit = null;

private ?int $offset = null;

private array $raw = [];

private array $relations = [];
Expand Down Expand Up @@ -67,6 +70,22 @@ public function all(mixed ...$bindings): array
return map($this->build($bindings))->collection()->to($this->modelClass);
}

/**
* @param \Closure(TModelClass[] $models): void $closure
*/
public function chunk(Closure $closure, int $amountPerChunk = 200): void
{
$offset = 0;

do {
$data = $this->clone()->limit($amountPerChunk)->offset($offset)->all();

$offset += count($data);

$closure($data);
} while ($data !== []);
}

/** @return self<TModelClass> */
public function where(string $where, mixed ...$bindings): self
{
Expand All @@ -93,6 +112,14 @@ public function limit(int $limit): self
return $this;
}

/** @return self<TModelClass> */
public function offset(int $offset): self
{
$this->offset = $offset;

return $this;
}

/** @return self<TModelClass> */
public function raw(string $raw): self
{
Expand Down Expand Up @@ -177,6 +204,10 @@ private function build(array $bindings): Query
$statements[] = sprintf('LIMIT %s', $this->limit);
}

if ($this->offset) {
$statements[] = sprintf('OFFSET %s', $this->offset);
}

if ($this->raw !== []) {
$statements[] = implode(', ', $this->raw);
}
Expand All @@ -197,4 +228,9 @@ private function getRelations(ModelDefinition $modelDefinition): array

return $relations;
}

private function clone(): self
{
return clone $this;
}
}
46 changes: 46 additions & 0 deletions tests/Integration/Database/Builder/ModelQueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,52 @@ public function test_limit(): void
$this->assertSame('B', $books[1]->title);
}

public function test_offset(): void
{
$this->migrate(
CreateMigrationsTable::class,
CreateAuthorTable::class,
CreateBookTable::class,
);

(Book::new(title: 'A'))->save();
(Book::new(title: 'B'))->save();
(Book::new(title: 'C'))->save();
(Book::new(title: 'D'))->save();

$books = Book::query()->limit(2)->offset(2)->all();

$this->assertCount(2, $books);
$this->assertSame('C', $books[0]->title);
$this->assertSame('D', $books[1]->title);
}

public function test_chunk(): void
{
$this->migrate(
CreateMigrationsTable::class,
CreateAuthorTable::class,
CreateBookTable::class,
);

(Book::new(title: 'A'))->save();
(Book::new(title: 'B'))->save();
(Book::new(title: 'C'))->save();
(Book::new(title: 'D'))->save();

$results = [];
Book::query()->chunk(function (array $chunk) use (&$results) {
$results = [...$results, ...$chunk];
}, 2);
$this->assertCount(4, $results);

$results = [];
Book::query()->where('title <> "A"')->chunk(function (array $chunk) use (&$results) {
$results = [...$results, ...$chunk];
}, 2);
$this->assertCount(3, $results);
}

public function test_raw(): void
{
$this->migrate(
Expand Down

0 comments on commit e332bbd

Please sign in to comment.