Skip to content

Commit 7ecfdc6

Browse files
committed
-
1 parent fb48de3 commit 7ecfdc6

File tree

2 files changed

+55
-6
lines changed

2 files changed

+55
-6
lines changed

src/Relations/HasOne.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
use Illuminate\Database\Eloquent\Builder;
88
use Illuminate\Database\Eloquent\Model;
99
use Illuminate\Database\Eloquent\Relations\HasOne as EloquentHasOne;
10+
use Illuminate\Support\Arr;
11+
12+
use function is_null;
1013

1114
class HasOne extends EloquentHasOne
1215
{
@@ -38,6 +41,49 @@ public function getRelationExistenceQuery(Builder $query, Builder $parentQuery,
3841
return $query->select($foreignKey)->where($foreignKey, 'exists', true);
3942
}
4043

44+
public function ofMany($column = 'id', $aggregate = 'MAX', $relation = null)
45+
{
46+
return parent::ofMany($column, $aggregate, $relation);
47+
$this->ofMany = true;
48+
49+
$order = match($aggregate) {
50+
'MAX' => -1,
51+
'MIN' => 1,
52+
default => throw new \LogicException('Invalid aggregate fonction for ofMany relation. Available aggregates: MIN, MAX'),
53+
};
54+
}
55+
56+
protected function newOneOfManySubQuery($groupBy, $columns = null, $aggregate = null)
57+
{
58+
$subQuery = $this->query->getModel()
59+
->newQuery()
60+
->withoutGlobalScopes($this->removedScopes());
61+
62+
foreach (Arr::wrap($groupBy) as $group) {
63+
$subQuery->groupBy($this->qualifyRelatedColumn($group));
64+
}
65+
66+
if (! is_null($columns)) {
67+
foreach ($columns as $key => $column) {
68+
$aggregatedColumn = $subQuery->qualifyColumn($column);
69+
70+
if ($key === 0) {
71+
$aggregatedColumn = ['$' . strtolower($aggregate) => '$' . $aggregatedColumn];
72+
} else {
73+
$aggregatedColumn = ['$min' => '$' . $aggregatedColumn];
74+
}
75+
76+
$subQuery->project([$column . '_aggregate' => $aggregatedColumn]);
77+
}
78+
}
79+
80+
$this->addOneOfManySubQueryConstraints($subQuery, column: null, aggregate: $aggregate);
81+
82+
return $subQuery;
83+
84+
parent::newOneOfManySubQuery($groupBy, $columns, $aggregate);
85+
}
86+
4187
/**
4288
* Get the name of the "where in" method for eager loading.
4389
*

tests/Eloquent/DatabaseEloquentHasOneOfManyTest.php

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public function testEagerLoadingAppliesConstraintsToInnerJoinSubQuery()
105105
$user = HasOneOfManyTestUser::create();
106106
$relation = $user->latest_login();
107107
$relation->addEagerConstraints([$user]);
108-
$this->assertSame('select MAX("logins"."id") as "id_aggregate", "logins"."user_id" from "logins" where "logins"."user_id" = ? and "logins"."user_id" is not null and "logins"."user_id" in (1) group by "logins"."user_id"', $relation->getOneOfManySubQuery()->toSql());
108+
$this->assertSame('select MAX("logins"."id") as "id_aggregate", "logins"."user_id" from "logins" where "logins"."user_id" = ? and "logins"."user_id" is not null and "logins"."user_id" in (1) group by "logins"."user_id"', $relation->getOneOfManySubQuery()->toMql());
109109
}
110110

111111
public function testGlobalScopeIsNotAppliedWhenRelationIsDefinedWithoutGlobalScope()
@@ -117,7 +117,7 @@ public function testGlobalScopeIsNotAppliedWhenRelationIsDefinedWithoutGlobalSco
117117
$user = HasOneOfManyTestUser::create();
118118
$relation = $user->latest_login_without_global_scope();
119119
$relation->addEagerConstraints([$user]);
120-
$this->assertSame('select "logins".* from "logins" inner join (select MAX("logins"."id") as "id_aggregate", "logins"."user_id" from "logins" where "logins"."user_id" = ? and "logins"."user_id" is not null and "logins"."user_id" in (1) group by "logins"."user_id") as "latestOfMany" on "latestOfMany"."id_aggregate" = "logins"."id" and "latestOfMany"."user_id" = "logins"."user_id" where "logins"."user_id" = ? and "logins"."user_id" is not null', $relation->getQuery()->toSql());
120+
$this->assertSame('select "logins".* from "logins" inner join (select MAX("logins"."id") as "id_aggregate", "logins"."user_id" from "logins" where "logins"."user_id" = ? and "logins"."user_id" is not null and "logins"."user_id" in (1) group by "logins"."user_id") as "latestOfMany" on "latestOfMany"."id_aggregate" = "logins"."id" and "latestOfMany"."user_id" = "logins"."user_id" where "logins"."user_id" = ? and "logins"."user_id" is not null', $relation->getQuery()->toMql());
121121

122122
HasOneOfManyTestLogin::addGlobalScope('test', function ($query) {
123123
});
@@ -131,7 +131,7 @@ public function testGlobalScopeIsNotAppliedWhenRelationIsDefinedWithoutGlobalSco
131131

132132
$user = HasOneOfManyTestUser::create();
133133
$relation = $user->price_without_global_scope();
134-
$this->assertSame('select "prices".* from "prices" inner join (select max("prices"."id") as "id_aggregate", min("prices"."published_at") as "published_at_aggregate", "prices"."user_id" from "prices" inner join (select max("prices"."published_at") as "published_at_aggregate", "prices"."user_id" from "prices" where "published_at" < ? and "prices"."user_id" = ? and "prices"."user_id" is not null group by "prices"."user_id") as "price_without_global_scope" on "price_without_global_scope"."published_at_aggregate" = "prices"."published_at" and "price_without_global_scope"."user_id" = "prices"."user_id" where "published_at" < ? group by "prices"."user_id") as "price_without_global_scope" on "price_without_global_scope"."id_aggregate" = "prices"."id" and "price_without_global_scope"."published_at_aggregate" = "prices"."published_at" and "price_without_global_scope"."user_id" = "prices"."user_id" where "prices"."user_id" = ? and "prices"."user_id" is not null', $relation->getQuery()->toSql());
134+
$this->assertSame('select "prices".* from "prices" inner join (select max("prices"."id") as "id_aggregate", min("prices"."published_at") as "published_at_aggregate", "prices"."user_id" from "prices" inner join (select max("prices"."published_at") as "published_at_aggregate", "prices"."user_id" from "prices" where "published_at" < ? and "prices"."user_id" = ? and "prices"."user_id" is not null group by "prices"."user_id") as "price_without_global_scope" on "price_without_global_scope"."published_at_aggregate" = "prices"."published_at" and "price_without_global_scope"."user_id" = "prices"."user_id" where "published_at" < ? group by "prices"."user_id") as "price_without_global_scope" on "price_without_global_scope"."id_aggregate" = "prices"."id" and "price_without_global_scope"."published_at_aggregate" = "prices"."published_at" and "price_without_global_scope"."user_id" = "prices"."user_id" where "prices"."user_id" = ? and "prices"."user_id" is not null', $relation->getQuery()->toMql());
135135

136136
HasOneOfManyTestPrice::addGlobalScope('test', function ($query) {
137137
});
@@ -145,7 +145,7 @@ public function testQualifyingSubSelectColumn()
145145

146146
public function testItFailsWhenUsingInvalidAggregate()
147147
{
148-
$this->expectException(InvalidArgumentException::class);
148+
$this->expectException(\InvalidArgumentException::class);
149149
$this->expectExceptionMessage('Invalid aggregate [count] used within ofMany relation. Available aggregates: MIN, MAX');
150150
$user = HasOneOfManyTestUser::make();
151151
$user->latest_login_with_invalid_aggregate();
@@ -291,6 +291,7 @@ public function testWithHasNested()
291291

292292
public function testHasCount()
293293
{
294+
self::markTestSkipped('withCount not supported, PHPORM-238');
294295
$user = HasOneOfManyTestUser::create();
295296
$user->logins()->create();
296297
$user->logins()->create();
@@ -430,7 +431,8 @@ public function testEagerLoadingWithMultipleAggregates()
430431

431432
public function testWithExists()
432433
{
433-
$user = HasOneOfManyTestUser::create();
434+
self::markTestSkipped('withExists not supported, PHPORM-285');
435+
HasOneOfManyTestUser::create();
434436

435437
$user = HasOneOfManyTestUser::withExists('latest_login')->first();
436438
$this->assertFalse($user->latest_login_exists);
@@ -442,7 +444,8 @@ public function testWithExists()
442444

443445
public function testWithExistsWithConstraintsInJoinSubSelect()
444446
{
445-
$user = HasOneOfManyTestUser::create();
447+
self::markTestSkipped('withExists not supported, PHPORM-285');
448+
HasOneOfManyTestUser::create();
446449

447450
$user = HasOneOfManyTestUser::withExists('foo_state')->first();
448451

0 commit comments

Comments
 (0)