Skip to content

Commit 1279dfd

Browse files
committed
wip
1 parent b353352 commit 1279dfd

File tree

15 files changed

+150
-12
lines changed

15 files changed

+150
-12
lines changed

packages/database/src/BelongsTo.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,28 @@ final class BelongsTo implements Relation
1818
{
1919
public PropertyReflector $property;
2020

21+
private ?string $parent = null;
22+
2123
public function __construct(
2224
private readonly ?string $relationJoin = null,
2325
private readonly ?string $ownerJoin = null,
2426
) {}
2527

28+
public function setParent(string $name): self
29+
{
30+
$this->parent = $name;
31+
32+
return $this;
33+
}
34+
2635
public function getOwnerFieldName(): string
2736
{
2837
if ($this->ownerJoin) {
29-
return explode('.', $this->ownerJoin)[1];
38+
if (strpos($this->ownerJoin, '.') !== false) {
39+
return explode('.', $this->ownerJoin)[1];
40+
} else {
41+
return $this->ownerJoin;
42+
}
3043
}
3144

3245
$relationModel = model($this->property->getType()->asClass());
@@ -40,7 +53,9 @@ public function getSelectFields(): ImmutableArray
4053

4154
return $relationModel
4255
->getSelectFields()
43-
->map(fn ($field) => new FieldStatement($relationModel->getTableName() . '.' . $field)->withAlias());
56+
->map(fn ($field) => new FieldStatement(
57+
$relationModel->getTableName() . '.' . $field
58+
)->withAlias()->withAliasPrefix($this->parent));
4459
}
4560

4661
public function getJoinStatement(): JoinStatement

packages/database/src/Builder/ModelInspector.php

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Tempest\Validation\SkipValidation;
1919
use Tempest\Validation\Validator;
2020

21+
use function Tempest\Database\model;
2122
use function Tempest\get;
2223
use function Tempest\Support\arr;
2324
use function Tempest\Support\str;
@@ -28,7 +29,8 @@ final class ModelInspector
2829

2930
public function __construct(
3031
private object|string $model,
31-
) {
32+
)
33+
{
3234
if ($this->model instanceof ClassReflector) {
3335
$this->modelClass = $this->model;
3436
} else {
@@ -219,6 +221,38 @@ public function getRelation(string|PropertyReflector $name): ?Relation
219221
return $this->getBelongsTo($name) ?? $this->getHasOne($name) ?? $this->getHasMany($name);
220222
}
221223

224+
public function resolveRelations(string $relationString, string $parent = ''): array
225+
{
226+
if ($relationString === '') {
227+
return [];
228+
}
229+
230+
$relationNames = explode('.', $relationString);
231+
232+
$currentRelationName = $relationNames[0];
233+
234+
$currentRelation = $this->getRelation($currentRelationName);
235+
236+
if ($currentRelation === null) {
237+
return [];
238+
}
239+
240+
unset($relationNames[0]);
241+
242+
$newRelationString = implode('.', $relationNames);
243+
$currentRelation->setParent($parent);
244+
$newParent = ltrim(sprintf(
245+
'%s.%s',
246+
$parent,
247+
$currentRelationName,
248+
), '.');
249+
250+
return [
251+
$currentRelation,
252+
...model($currentRelation->property->getType()->asClass())->resolveRelations($newRelationString, $newParent)
253+
];
254+
}
255+
222256
public function getEagerRelations(): array
223257
{
224258
if (! $this->isObjectModel()) {

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,14 +258,14 @@ private function getIncludedRelations(): array
258258

259259
$relations = $definition->getEagerRelations();
260260

261-
foreach ($this->relations as $relation) {
262-
$relation = $definition->getRelation($relation);
261+
foreach ($this->relations as $relationString) {
262+
$resolvedRelations = $definition->resolveRelations($relationString);
263263

264-
if (! $relation) {
264+
if ($resolvedRelations === []) {
265265
continue;
266266
}
267267

268-
$relations[$relation->property->getName()] = $relation;
268+
$relations = [...$relations, ...$resolvedRelations];
269269
}
270270

271271
return $relations;

packages/database/src/HasMany.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,29 @@ final class HasMany implements Relation
1818
{
1919
public PropertyReflector $property;
2020

21+
private ?string $parent = null;
22+
2123
public function __construct(
2224
public ?string $ownerJoin = null,
2325
public ?string $relationJoin = null,
2426
) {}
2527

28+
public function setParent(string $name): self
29+
{
30+
$this->parent = $name;
31+
32+
return $this;
33+
}
34+
2635
public function getSelectFields(): ImmutableArray
2736
{
2837
$relationModel = model($this->property->getIterableType()->asClass());
2938

3039
return $relationModel
3140
->getSelectFields()
32-
->map(fn ($field) => new FieldStatement($relationModel->getTableName() . '.' . $field)->withAlias());
41+
->map(fn ($field) => new FieldStatement(
42+
$relationModel->getTableName() . '.' . $field,
43+
)->withAlias()->withAliasPrefix($this->parent));
3344
}
3445

3546
public function idField(): string

packages/database/src/HasOne.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,29 @@ final class HasOne implements Relation
1818
{
1919
public PropertyReflector $property;
2020

21+
private ?string $parent = null;
22+
2123
public function __construct(
2224
public ?string $ownerJoin = null,
2325
public ?string $relationJoin = null,
2426
) {}
2527

28+
public function setParent(string $name): self
29+
{
30+
$this->parent = $name;
31+
32+
return $this;
33+
}
34+
2635
public function getSelectFields(): ImmutableArray
2736
{
2837
$relationModel = model($this->property->getType()->asClass());
2938

3039
return $relationModel
3140
->getSelectFields()
32-
->map(fn ($field) => new FieldStatement($relationModel->getTableName() . '.' . $field)->withAlias());
41+
->map(fn ($field) => new FieldStatement(
42+
$relationModel->getTableName() . '.' . $field,
43+
)->withAlias()->withAliasPrefix($this->parent));
3344
}
3445

3546
public function getJoinStatement(): JoinStatement

packages/database/src/QueryStatements/FieldStatement.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
final class FieldStatement implements QueryStatement
1212
{
1313
private bool $withAlias = false;
14+
private ?string $aliasPrefix = null;
1415

1516
public function __construct(
1617
private readonly string|Stringable $field,
@@ -27,7 +28,8 @@ public function compile(DatabaseDialect $dialect): string
2728

2829
if ($this->withAlias) {
2930
$alias = sprintf(
30-
'`%s`',
31+
'`%s%s`',
32+
$this->aliasPrefix ? "$this->aliasPrefix." : "",
3133
str_replace('`', '', $field),
3234
);
3335
}
@@ -52,6 +54,13 @@ public function compile(DatabaseDialect $dialect): string
5254
return sprintf('%s AS `%s`', $field, trim($alias, '`'));
5355
}
5456

57+
public function withAliasPrefix(?string $prefix = null): self
58+
{
59+
$this->aliasPrefix = $prefix;
60+
61+
return $this;
62+
}
63+
5564
public function withAlias(): self
5665
{
5766
$this->withAlias = true;

packages/database/src/Relation.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
interface Relation extends PropertyAttribute
1010
{
11+
public function setParent(string $name): self;
12+
1113
public function getSelectFields(): ImmutableArray;
1214

1315
public function getJoinStatement(): JoinStatement;

packages/database/tests/QueryStatements/FieldStatementTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,15 @@ public function test_with_alias(): void
8181
->compile(DatabaseDialect::MYSQL),
8282
);
8383
}
84+
85+
public function test_with_alias_prefix(): void
86+
{
87+
$this->assertSame(
88+
'authors.name AS `parent.authors.name`',
89+
new FieldStatement('authors.name')
90+
->withAlias()
91+
->withAliasPrefix('parent')
92+
->compile(DatabaseDialect::SQLITE),
93+
);
94+
}
8495
}

tests/Integration/Database/BelongsToTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,15 @@ public function test_belongs_to_with_owner_join_field_and_table(): void
7575
$relation->getJoinStatement()->compile(DatabaseDialect::SQLITE),
7676
);
7777
}
78+
79+
public function test_belongs_to_with_parent(): void
80+
{
81+
$model = model(OwnerModel::class);
82+
$relation = $model->getRelation('relation')->setParent('parent');
83+
84+
$this->assertSame(
85+
'relation.name AS `parent.relation.name`',
86+
$relation->getSelectFields()[0]->compile(DatabaseDialect::SQLITE),
87+
);
88+
}
7889
}

tests/Integration/Database/Fixtures/HasOneRelationModel.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@ final class HasOneRelationModel
2424

2525
#[HasOne(relationJoin: 'overwritten.overwritten_id')]
2626
public OwnerModel $relationJoinFieldAndTable;
27+
28+
public string $name;
2729
}

0 commit comments

Comments
 (0)