Skip to content

Commit b6252dc

Browse files
feat(database): add a Virtual attribute to exclude model properties from query builder (#966)
Co-authored-by: Brent Roose <[email protected]>
1 parent 749e97d commit b6252dc

File tree

4 files changed

+88
-21
lines changed

4 files changed

+88
-21
lines changed

src/Tempest/Database/src/Builder/ModelQueryBuilder.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
namespace Tempest\Database\Builder;
66

77
use Closure;
8-
use Tempest\Database\DatabaseModel;
98
use Tempest\Database\Id;
10-
use Tempest\Database\Query;
119
use function Tempest\map;
10+
use Tempest\Database\Query;
11+
use function Tempest\reflect;
12+
use Tempest\Database\Virtual;
13+
use Tempest\Database\DatabaseModel;
1214

1315
/**
1416
* @template TModelClass of DatabaseModel
@@ -165,6 +167,8 @@ private function build(array $bindings): Query
165167

166168
$fields = $modelDefinition->getFieldNames();
167169

170+
$fields = array_filter($fields, fn(FieldName $field) => !(reflect($this->modelClass, $field->fieldName)->hasAttribute(Virtual::class)));
171+
168172
foreach ($relations as $relation) {
169173
$fields = [...$fields, ...$relation->getFieldNames()];
170174
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\Database;
6+
7+
use Attribute;
8+
9+
#[Attribute(Attribute::TARGET_PROPERTY)]
10+
final readonly class Virtual
11+
{
12+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Tempest\Fixtures\Models;
6+
7+
use Tempest\Database\Virtual;
8+
use Tempest\Database\DatabaseModel;
9+
use Tempest\Database\IsDatabaseModel;
10+
use Tempest\Database\Builder\TableName;
11+
12+
final class AWithVirtual implements DatabaseModel
13+
{
14+
use IsDatabaseModel;
15+
16+
#[Virtual]
17+
public int $fake {
18+
get => $this->id->id * -1;
19+
}
20+
21+
public function __construct(
22+
public B $b,
23+
) {
24+
}
25+
26+
public static function table(): TableName
27+
{
28+
return new TableName('a');
29+
}
30+
}

tests/Integration/ORM/IsDatabaseModelTest.php

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,38 @@
66

77
use Carbon\Carbon;
88
use DateTimeImmutable;
9-
use Tempest\Database\Exceptions\MissingRelation;
10-
use Tempest\Database\Exceptions\MissingValue;
119
use Tempest\Database\Id;
12-
use Tempest\Database\Migrations\CreateMigrationsTable;
13-
use Tests\Tempest\Fixtures\Migrations\CreateAuthorTable;
14-
use Tests\Tempest\Fixtures\Migrations\CreateBookTable;
10+
use function Tempest\map;
1511
use Tests\Tempest\Fixtures\Models\A;
16-
use Tests\Tempest\Fixtures\Models\AWithEager;
17-
use Tests\Tempest\Fixtures\Models\AWithLazy;
18-
use Tests\Tempest\Fixtures\Models\AWithValue;
1912
use Tests\Tempest\Fixtures\Models\B;
2013
use Tests\Tempest\Fixtures\Models\C;
21-
use Tests\Tempest\Fixtures\Modules\Books\Models\Author;
22-
use Tests\Tempest\Fixtures\Modules\Books\Models\AuthorType;
14+
use Tests\Tempest\Fixtures\Models\AWithLazy;
15+
use Tempest\Database\Exceptions\MissingValue;
16+
use Tests\Tempest\Fixtures\Models\AWithEager;
17+
use Tests\Tempest\Fixtures\Models\AWithValue;
18+
use Tests\Tempest\Fixtures\Models\AWithVirtual;
19+
use Tempest\Database\Exceptions\MissingRelation;
20+
use Tests\Tempest\Integration\ORM\Models\CasterEnum;
21+
use Tests\Tempest\Integration\ORM\Models\ChildModel;
2322
use Tests\Tempest\Fixtures\Modules\Books\Models\Book;
24-
use Tests\Tempest\Integration\FrameworkIntegrationTestCase;
23+
use Tests\Tempest\Integration\ORM\Models\CarbonModel;
24+
use Tests\Tempest\Integration\ORM\Models\CasterModel;
25+
use Tests\Tempest\Integration\ORM\Models\ParentModel;
26+
use Tempest\Database\Migrations\CreateMigrationsTable;
27+
use Tests\Tempest\Fixtures\Migrations\CreateBookTable;
28+
use Tests\Tempest\Integration\ORM\Models\ThroughModel;
29+
use Tests\Tempest\Fixtures\Modules\Books\Models\Author;
30+
use Tests\Tempest\Fixtures\Migrations\CreateAuthorTable;
2531
use Tests\Tempest\Integration\ORM\Migrations\CreateATable;
2632
use Tests\Tempest\Integration\ORM\Migrations\CreateBTable;
33+
use Tests\Tempest\Integration\ORM\Migrations\CreateCTable;
34+
use Tests\Tempest\Fixtures\Modules\Books\Models\AuthorType;
35+
use Tests\Tempest\Integration\FrameworkIntegrationTestCase;
2736
use Tests\Tempest\Integration\ORM\Migrations\CreateCarbonModelTable;
2837
use Tests\Tempest\Integration\ORM\Migrations\CreateCasterModelTable;
29-
use Tests\Tempest\Integration\ORM\Migrations\CreateCTable;
3038
use Tests\Tempest\Integration\ORM\Migrations\CreateHasManyChildTable;
3139
use Tests\Tempest\Integration\ORM\Migrations\CreateHasManyParentTable;
3240
use Tests\Tempest\Integration\ORM\Migrations\CreateHasManyThroughTable;
33-
use Tests\Tempest\Integration\ORM\Models\CarbonModel;
34-
use Tests\Tempest\Integration\ORM\Models\CasterEnum;
35-
use Tests\Tempest\Integration\ORM\Models\CasterModel;
36-
use Tests\Tempest\Integration\ORM\Models\ChildModel;
37-
use Tests\Tempest\Integration\ORM\Models\ParentModel;
38-
use Tests\Tempest\Integration\ORM\Models\ThroughModel;
39-
use function Tempest\map;
4041

4142
/**
4243
* @internal
@@ -399,6 +400,26 @@ public function test_no_result(): void
399400
$this->assertNull(A::query()->first());
400401
}
401402

403+
public function test_virtual_property(): void
404+
{
405+
$this->migrate(
406+
CreateMigrationsTable::class,
407+
CreateATable::class,
408+
CreateBTable::class,
409+
CreateCTable::class,
410+
);
411+
412+
(new A(
413+
b: new B(
414+
c: new C(name: 'test'),
415+
),
416+
))->save();
417+
418+
$a = AWithVirtual::query()->first();
419+
420+
$this->assertSame($a->id->id * -1, $a->fake);
421+
}
422+
402423
public function test_update_or_create(): void
403424
{
404425
$this->migrate(

0 commit comments

Comments
 (0)