Skip to content

Commit f4f7600

Browse files
committed
wip
1 parent 1b06332 commit f4f7600

File tree

9 files changed

+105
-34
lines changed

9 files changed

+105
-34
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Tempest\Database\Builder\QueryBuilders;
4+
5+
use Tempest\Database\Query;
6+
7+
interface BuildsQuery
8+
{
9+
public function build(mixed ...$bindings): Query;
10+
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
/**
1616
* @template TModelClass of object
1717
*/
18-
final class CountQueryBuilder
18+
final class CountQueryBuilder implements BuildsQuery
1919
{
2020
use HasConditions;
2121

@@ -93,7 +93,7 @@ public function toSql(): string
9393
return $this->build()->getSql();
9494
}
9595

96-
public function build(array $bindings = []): Query
96+
public function build(mixed ...$bindings): Query
9797
{
9898
return new Query($this->count, [...$this->bindings, ...$bindings]);
9999
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
/**
1515
* @template TModelClass of object
1616
*/
17-
final class DeleteQueryBuilder
17+
final class DeleteQueryBuilder implements BuildsQuery
1818
{
1919
use HasConditions;
2020

@@ -61,8 +61,8 @@ public function bind(mixed ...$bindings): self
6161
return $this;
6262
}
6363

64-
public function build(): Query
64+
public function build(mixed ...$bindings): Query
6565
{
66-
return new Query($this->delete, $this->bindings);
66+
return new Query($this->delete, [...$this->bindings, ...$bindings]);
6767
}
6868
}

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

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Tempest\Database\Builder\QueryBuilders;
44

5+
use Closure;
56
use Tempest\Database\Builder\ModelDefinition;
67
use Tempest\Database\Builder\TableDefinition;
78
use Tempest\Database\Id;
@@ -11,27 +12,37 @@
1112
use Tempest\Reflection\ClassReflector;
1213
use Tempest\Support\Arr\ImmutableArray;
1314

14-
final readonly class InsertQueryBuilder
15+
final class InsertQueryBuilder implements BuildsQuery
1516
{
1617
private InsertStatement $insert;
1718

19+
private array $after = [];
20+
1821
public function __construct(
19-
private string|object $model,
20-
private array $rows,
21-
private SerializerFactory $serializerFactory,
22+
private readonly string|object $model,
23+
private readonly array $rows,
24+
private readonly SerializerFactory $serializerFactory,
2225
) {
2326
$this->insert = new InsertStatement($this->resolveTableDefinition());
2427
}
2528

2629
public function execute(mixed ...$bindings): Id
2730
{
28-
return $this->build()->execute(...$bindings);
31+
$id = $this->build()->execute(...$bindings);
32+
33+
foreach ($this->after as $after) {
34+
$query = $after($id);
35+
36+
if ($query instanceof BuildsQuery) {
37+
$query->build()->execute();
38+
}
39+
}
40+
41+
return $id;
2942
}
3043

31-
public function build(): Query
44+
public function build(mixed ...$bindings): Query
3245
{
33-
$bindings = [];
34-
3546
foreach ($this->resolveEntries() as $entry) {
3647
$this->insert->addEntry($entry);
3748

@@ -46,6 +57,13 @@ public function build(): Query
4657
);
4758
}
4859

60+
public function then(Closure ...$callbacks): self
61+
{
62+
$this->after = [...$this->after, ...$callbacks];
63+
64+
return $this;
65+
}
66+
4967
private function resolveEntries(): array
5068
{
5169
$entries = [];
@@ -78,7 +96,7 @@ private function resolveEntries(): array
7896

7997
$value = $property->getValue($model);
8098

81-
// BelongsTo and HasMany relations are included
99+
// BelongsTo and reverse HasMany relations are included
82100
if ($property->getType()->isRelation()) {
83101
$column .= '_id';
84102

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
/**
2727
* @template TModelClass of object
2828
*/
29-
final class SelectQueryBuilder
29+
final class SelectQueryBuilder implements BuildsQuery
3030
{
3131
use HasConditions;
3232

@@ -57,7 +57,7 @@ public function __construct(string|object $model, ?ImmutableArray $columns = nul
5757
*/
5858
public function first(mixed ...$bindings): mixed
5959
{
60-
$query = $this->build($bindings);
60+
$query = $this->build(...$bindings);
6161

6262
$result = map($query)->collection()->to($this->modelClass);
6363

@@ -79,7 +79,7 @@ public function get(Id $id): mixed
7979
/** @return TModelClass[] */
8080
public function all(mixed ...$bindings): array
8181
{
82-
return map($this->build($bindings))->collection()->to($this->modelClass);
82+
return map($this->build(...$bindings))->collection()->to($this->modelClass);
8383
}
8484

8585
/**
@@ -182,7 +182,7 @@ public function toSql(): string
182182
return $this->build()->getSql();
183183
}
184184

185-
public function build(array $bindings = []): Query
185+
public function build(mixed ...$bindings): Query
186186
{
187187
$resolvedRelations = $this->resolveRelations();
188188

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use function Tempest\Database\model;
1616
use function Tempest\Support\arr;
1717

18-
final class UpdateQueryBuilder
18+
final class UpdateQueryBuilder implements BuildsQuery
1919
{
2020
use HasConditions;
2121

@@ -61,7 +61,7 @@ public function bind(mixed ...$bindings): self
6161
return $this;
6262
}
6363

64-
public function build(): Query
64+
public function build(mixed ...$bindings): Query
6565
{
6666
$values = $this->resolveValues();
6767

@@ -73,8 +73,6 @@ public function build(): Query
7373
$this->where('`id` = ?', id: $this->model->id->id);
7474
}
7575

76-
$bindings = [];
77-
7876
foreach ($values as $value) {
7977
$bindings[] = $value;
8078
}

packages/database/src/Query.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ final class Query
1313
public function __construct(
1414
public string|QueryStatement $sql,
1515
public array $bindings = [],
16+
/** @var \Closure[] $executeAfter */
17+
public array $executeAfter = [],
1618
) {}
1719

1820
public function execute(mixed ...$bindings): Id
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Tempest\Fixtures\Migrations;
6+
7+
use Tempest\Database\DatabaseMigration;
8+
use Tempest\Database\QueryStatement;
9+
use Tempest\Database\QueryStatements\CreateTableStatement;
10+
use Tempest\Database\QueryStatements\DropTableStatement;
11+
use Tests\Tempest\Fixtures\Modules\Books\Models\Book;
12+
use Tests\Tempest\Fixtures\Modules\Books\Models\Chapter;
13+
14+
final class CreateChapterTable implements DatabaseMigration
15+
{
16+
private(set) string $name = '0000-00-00_create_chapters_table';
17+
18+
public function up(): QueryStatement
19+
{
20+
return CreateTableStatement::forModel(Chapter::class)
21+
->primary()
22+
->text('title')
23+
->text('contents', default: '')
24+
->belongsTo('chapters.book_id', 'books.id');
25+
}
26+
27+
public function down(): QueryStatement
28+
{
29+
return DropTableStatement::forModel(Book::class);
30+
}
31+
}

tests/Integration/Database/Builder/InsertQueryBuilderTest.php

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
namespace Tests\Tempest\Integration\Database\Builder;
44

5-
use Tempest\Database\Exceptions\CannotInsertHasManyRelation;
6-
use Tempest\Database\Exceptions\CannotUpdateHasManyRelation;
75
use Tempest\Database\Id;
6+
use Tempest\Database\Migrations\CreateMigrationsTable;
87
use Tempest\Database\Query;
8+
use Tests\Tempest\Fixtures\Migrations\CreateBookTable;
9+
use Tests\Tempest\Fixtures\Migrations\CreateChapterTable;
910
use Tests\Tempest\Fixtures\Modules\Books\Models\Author;
1011
use Tests\Tempest\Fixtures\Modules\Books\Models\AuthorType;
1112
use Tests\Tempest\Fixtures\Modules\Books\Models\Book;
@@ -151,15 +152,26 @@ public function test_insert_on_model_table_with_existing_relation(): void
151152

152153
public function test_attach_new_has_many_relation_on_update(): void
153154
{
154-
$this->markTestSkipped('Not implemented yet');
155-
156-
// query(Book::class)
157-
// ->insert(
158-
// title: 'Timeline Taxi',
159-
// chapters: [
160-
// Chapter::new(title: 'Chapter 01'),
161-
// ],
162-
// )
163-
// ->build();
155+
$this->migrate(CreateMigrationsTable::class, CreateBookTable::class, CreateChapterTable::class);
156+
157+
$id = query(Book::class)
158+
->insert(title: 'Timeline Taxi')
159+
->then(
160+
fn (Id $id) => query(Chapter::class)->insert(
161+
['title' => 'Chapter 01', 'book_id' => $id],
162+
['title' => 'Chapter 02', 'book_id' => $id],
163+
),
164+
fn (Id $id) => query(Chapter::class)->insert(
165+
['title' => 'Chapter 03', 'book_id' => $id],
166+
),
167+
)
168+
->execute();
169+
170+
$book = Book::select()->with('chapters')->get($id);
171+
172+
$this->assertCount(3, $book->chapters);
173+
$this->assertSame('Chapter 01', $book->chapters[1]->title);
174+
$this->assertSame('Chapter 02', $book->chapters[2]->title);
175+
$this->assertSame('Chapter 03', $book->chapters[3]->title);
164176
}
165177
}

0 commit comments

Comments
 (0)