Skip to content

Commit cda9980

Browse files
committed
fix(core): sorting by multiple fields of the same relation
1 parent 4f57832 commit cda9980

File tree

3 files changed

+35
-4
lines changed

3 files changed

+35
-4
lines changed

src/Drivers/Standard/QueryBuilder.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ function ($relationQuery) use ($relationField, $requestedSearchString, $caseSens
395395
/**
396396
* Apply sorting to the given query builder based on the "sort" query parameter.
397397
*
398-
* @param Builder|Relation $query
398+
* @param Builder $query
399399
* @param Request $request
400400
*/
401401
public function applySortingToQuery($query, Request $request): void
@@ -431,8 +431,14 @@ public function applySortingToQuery($query, Request $request): void
431431
);
432432
$relationLocalKey = $this->relationsResolver->relationLocalKeyFromRelationInstance($relationInstance);
433433

434-
$query->leftJoin($relationTable, $relationForeignKey, '=', $relationLocalKey)
435-
->orderBy("$relationTable.$relationField", $direction)
434+
$requiresJoin = collect($query->toBase()->joins ?? [])
435+
->where('table', $relationTable)->isEmpty();
436+
437+
if ($requiresJoin) {
438+
$query->leftJoin($relationTable, $relationForeignKey, '=', $relationLocalKey);
439+
}
440+
441+
$query->orderBy("$relationTable.$relationField", $direction)
436442
->select($this->getQualifiedFieldName('*'));
437443
} else {
438444
$query->orderBy($this->getQualifiedFieldName($sortableField), $direction);

tests/Feature/StandardIndexSortingOperationsTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,4 +172,29 @@ public function getting_a_list_of_resources_asc_sorted_by_relation_field(): void
172172
$this->makePaginator([$postA, $postB, $postC], 'posts/search')
173173
);
174174
}
175+
176+
/** @test */
177+
public function getting_a_list_of_resources_asc_sorted_by_multiple_relation_fields(): void
178+
{
179+
$postC = factory(Post::class)->create(['user_id' => factory(User::class)->create(['name' => 'C'])->id])->fresh();
180+
$postB = factory(Post::class)->create(['user_id' => factory(User::class)->create(['name' => 'B'])->id])->fresh();
181+
$postA = factory(Post::class)->create(['user_id' => factory(User::class)->create(['name' => 'A'])->id])->fresh();
182+
183+
Gate::policy(Post::class, GreenPolicy::class);
184+
185+
$response = $this->post(
186+
'/api/posts/search',
187+
[
188+
'sort' => [
189+
['field' => 'user.name', 'direction' => 'asc'],
190+
['field' => 'user.email', 'direction' => 'asc'],
191+
],
192+
]
193+
);
194+
195+
$this->assertResourcesPaginated(
196+
$response,
197+
$this->makePaginator([$postA, $postB, $postC], 'posts/search')
198+
);
199+
}
175200
}

tests/Fixtures/app/Http/Controllers/PostsController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ protected function beforeSave(Request $request, $entity)
2727

2828
public function sortableBy(): array
2929
{
30-
return ['title', 'user.name', 'meta->nested_field'];
30+
return ['title', 'user.name', 'user.email', 'meta->nested_field'];
3131
}
3232

3333
public function filterableBy(): array

0 commit comments

Comments
 (0)