Skip to content

Commit ae006b5

Browse files
Merge pull request #622 from BinarCode/add-group-by
feat: Add groupBy as a new feature in repository
2 parents 34d05d9 + 3621f4c commit ae006b5

File tree

5 files changed

+103
-0
lines changed

5 files changed

+103
-0
lines changed

docs-v2/content/en/api/repositories.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,3 +819,14 @@ public static $withs = ['posts'];
819819
`withs` is not a typo. Laravel uses the `with` property on models, on repositories we use `$withs`, it's not a typo.
820820

821821
</alert>
822+
823+
## Group by
824+
825+
The group by filter is useful when you want to group the results by a certain column.
826+
827+
```php
828+
class PostRepository extends Repository
829+
{
830+
public static array $groupBy = ['user_id'];
831+
}
832+
```

src/Http/Requests/RestifyRequest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,9 @@ public function filters(): array
7777
? $this->input('filters', [])
7878
: (json_decode(base64_decode($this->input('filters')), true) ?? []);
7979
}
80+
81+
public function groupBy(): ?string
82+
{
83+
return $this->input('group_by');
84+
}
8085
}

src/Repositories/Repository.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ class Repository implements JsonSerializable, RestifySearchable
9191
*/
9292
public static array $sort;
9393

94+
/**
95+
* The list of fields that can be used for grouping.
96+
*/
97+
public static array $groupBy = [];
98+
9499
/**
95100
* Attribute that should be used for displaying single model.
96101
*/

src/Services/Search/RepositorySearchService.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ public function search(RestifyRequest $request, Repository $repository): Builder
4343

4444
$query = $this->applyFilters($request, $repository, $query);
4545

46+
$query = $this->applyGroupBy($request, $repository, $query);
47+
4648
$ordersBuilder = $this->prepareOrders($request, $query);
4749

4850
return tap(
@@ -217,6 +219,29 @@ protected function applyFilters(RestifyRequest $request, Repository $repository,
217219
return $query;
218220
}
219221

222+
protected function applyGroupBy(RestifyRequest $request, Repository $repository, $query)
223+
{
224+
if (! $request->has('group_by')) {
225+
return $query;
226+
}
227+
228+
$model = $query->getModel();
229+
$groupByColumns = explode(',', $request->input('group_by'));
230+
231+
foreach ($groupByColumns as $column) {
232+
if (! in_array($column, $repository::$groupBy)) {
233+
abort(422, sprintf(
234+
'The column [%s] is not allowed for grouping. Allowed columns are: %s',
235+
$column,
236+
implode(', ', $repository::$groupBy)
237+
));
238+
}
239+
$query->groupBy($model->qualifyColumn($column));
240+
}
241+
242+
return $query;
243+
}
244+
220245
public static function make(): static
221246
{
222247
return new static;
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
namespace Binaryk\LaravelRestify\Tests\Feature;
4+
5+
use Binaryk\LaravelRestify\Tests\Fixtures\User\User;
6+
use Binaryk\LaravelRestify\Tests\Fixtures\User\UserRepository;
7+
use Binaryk\LaravelRestify\Tests\IntegrationTestCase;
8+
9+
class RepositoryGroupByTest extends IntegrationTestCase
10+
{
11+
public function test_it_can_group_by_the_results(): void
12+
{
13+
User::factory(4)->create([
14+
'name' => 'John Doe',
15+
]);
16+
17+
User::factory(4)->create([
18+
'name' => 'Second John Doe',
19+
]);
20+
21+
UserRepository::$groupBy = ['name'];
22+
23+
$this->getJson(UserRepository::route(query: ['group_by' => 'name']))->assertJsonCount(2, 'data');
24+
}
25+
26+
public function test_it_can_group_by_the_results_multiple_columns(): void
27+
{
28+
User::factory(3)->create([
29+
'name' => 'John Doe',
30+
'avatar' => 'image.jpg',
31+
]);
32+
33+
User::factory(1)->create([
34+
'name' => 'Another John Doe',
35+
'avatar' => 'image.jpg',
36+
]);
37+
38+
UserRepository::$groupBy = ['name', 'avatar'];
39+
40+
$this->getJson(UserRepository::route(query: ['group_by' => 'name,avatar']))->assertJsonCount(2, 'data');
41+
}
42+
43+
public function test_it_can_not_group_by_the_results_because_wrong_column(): void
44+
{
45+
User::factory(4)->create([
46+
'name' => 'John Doe',
47+
]);
48+
49+
User::factory(4)->create([
50+
'name' => 'Second John Doe',
51+
]);
52+
53+
UserRepository::$groupBy = ['email'];
54+
55+
$this->getJson(UserRepository::route(query: ['group_by' => 'name']))->assertUnprocessable();
56+
}
57+
}

0 commit comments

Comments
 (0)