Skip to content

Commit 4fb626a

Browse files
committed
fix(database): support insertion of relations using create on models
1 parent 6996a5f commit 4fb626a

File tree

3 files changed

+111
-4
lines changed

3 files changed

+111
-4
lines changed

packages/database/src/Builder/ModelQueryBuilder.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,6 @@ public function create(mixed ...$params): object
241241

242242
$id = query($this->model)
243243
->insert($model)
244-
->build()
245244
->execute();
246245

247246
$inspector = inspect($this->model);

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

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -393,12 +393,26 @@ private function resolveObjectData(object $model): array
393393
continue;
394394
}
395395

396-
if ($definition->getHasMany($property->getName()) || $definition->getHasOne($property->getName())) {
396+
$propertyName = $property->getName();
397+
$value = $property->getValue($model);
398+
399+
if ($definition->getHasMany($propertyName)) {
400+
if (is_iterable($value)) {
401+
$this->addHasManyRelationCallback($propertyName, $value);
402+
}
403+
397404
continue;
398405
}
399406

400-
$column = $property->getName();
401-
$value = $property->getValue($model);
407+
if ($definition->getHasOne($propertyName)) {
408+
if (is_object($value) || is_array($value)) {
409+
$this->addHasOneRelationCallback($propertyName, $value);
410+
}
411+
412+
continue;
413+
}
414+
415+
$column = $propertyName;
402416

403417
if ($property->getType()->getName() === PrimaryKey::class && $value === null) {
404418
continue;

tests/Integration/Database/Builder/IsDatabaseModelTest.php

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Tempest\Database\DatabaseMigration;
1212
use Tempest\Database\Exceptions\RelationWasMissing;
1313
use Tempest\Database\Exceptions\ValueWasMissing;
14+
use Tempest\Database\HasMany;
1415
use Tempest\Database\HasOne;
1516
use Tempest\Database\IsDatabaseModel;
1617
use Tempest\Database\Migrations\CreateMigrationsTable;
@@ -636,6 +637,36 @@ public function test_date_field(): void
636637
$this->assertSame('2024-01-01 00:00:00', $model->phpDateTime->format('Y-m-d H:i:s'));
637638
$this->assertSame('2024-01-01 00:00:00', $model->tempestDateTime->format('yyyy-MM-dd HH:mm:ss'));
638639
}
640+
641+
public function test_model_create_with_has_many_relations(): void
642+
{
643+
$this->migrate(
644+
CreateMigrationsTable::class,
645+
CreateTestUserMigration::class,
646+
CreateTestPostMigration::class,
647+
);
648+
649+
$user = TestUser::create(
650+
name: 'Jon',
651+
posts: [
652+
new TestPost('hello', 'world'),
653+
new TestPost('foo', 'bar'),
654+
],
655+
);
656+
657+
$this->assertSame('Jon', $user->name);
658+
$this->assertInstanceOf(PrimaryKey::class, $user->id);
659+
660+
$posts = TestPost::select()
661+
->where('testuser_id', $user->id->value)
662+
->all();
663+
664+
$this->assertCount(2, $posts);
665+
$this->assertSame('hello', $posts[0]->title);
666+
$this->assertSame('world', $posts[0]->body);
667+
$this->assertSame('foo', $posts[1]->title);
668+
$this->assertSame('bar', $posts[1]->body);
669+
}
639670
}
640671

641672
final class Foo
@@ -983,3 +1014,66 @@ public function __construct(
9831014
public ?ChildModel $child2 = null,
9841015
) {}
9851016
}
1017+
1018+
final class TestUser
1019+
{
1020+
use IsDatabaseModel;
1021+
1022+
public PrimaryKey $id;
1023+
1024+
/** @var \Tests\Tempest\Integration\Database\Builder\TestPost[] */
1025+
#[HasMany]
1026+
public array $posts = [];
1027+
1028+
public function __construct(
1029+
public string $name,
1030+
) {}
1031+
}
1032+
1033+
final class TestPost
1034+
{
1035+
use IsDatabaseModel;
1036+
1037+
public PrimaryKey $id;
1038+
1039+
public function __construct(
1040+
public string $title,
1041+
public string $body,
1042+
) {}
1043+
}
1044+
1045+
final class CreateTestUserMigration implements DatabaseMigration
1046+
{
1047+
public string $name = '010_create_test_users';
1048+
1049+
public function up(): QueryStatement
1050+
{
1051+
return CreateTableStatement::forModel(TestUser::class)
1052+
->primary()
1053+
->text('name');
1054+
}
1055+
1056+
public function down(): ?QueryStatement
1057+
{
1058+
return null;
1059+
}
1060+
}
1061+
1062+
final class CreateTestPostMigration implements DatabaseMigration
1063+
{
1064+
public string $name = '011_create_test_posts';
1065+
1066+
public function up(): QueryStatement
1067+
{
1068+
return CreateTableStatement::forModel(TestPost::class)
1069+
->primary()
1070+
->belongsTo('test_posts.testuser_id', 'test_users.id')
1071+
->string('title')
1072+
->text('body');
1073+
}
1074+
1075+
public function down(): ?QueryStatement
1076+
{
1077+
return null;
1078+
}
1079+
}

0 commit comments

Comments
 (0)