Skip to content

Commit a51bbc3

Browse files
committed
✨ laravel scout integration
1 parent 941f0a0 commit a51bbc3

File tree

6 files changed

+166
-58
lines changed

6 files changed

+166
-58
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,5 +90,4 @@ Here is a quick look at what you can do using API search method:
9090

9191
- Metrics support
9292
- Refactor the response class
93-
- Plain text search using Laravel Scout
9493
- Alias for includes / aggregates

src/Query/ScoutBuilder.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public function search(array $parameters = [])
2323
{
2424
$this->resource->searchScoutQuery(app()->make(RestRequest::class), $this->queryBuilder);
2525

26-
$this->queryBuilder->query = request('search.text.value');
26+
$this->queryBuilder->query = $parameters['text']['value'] ?? '';
2727

2828
$this->when(isset($parameters['filters']), function () use ($parameters) {
2929
$this->applyFilters($parameters['filters']);
@@ -37,10 +37,7 @@ public function search(array $parameters = [])
3737
$this->applyInstructions($parameters['instructions']);
3838
});
3939

40-
// @TODO: UNIT TESTS !
41-
// @TODO: verify filters / instructions / sorts not passed
42-
43-
// @TODO: instructions ?
40+
// @TODO: instructions scout side ????
4441

4542
$this->queryBuilder
4643
->query(function (Builder $query) use ($parameters) {
@@ -51,6 +48,7 @@ public function search(array $parameters = [])
5148
'filters',
5249
'instructions',
5350
'sorts',
51+
'text'
5452
])
5553
->all()
5654
);

src/Rules/SearchRules.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,9 +251,13 @@ protected function instructionsRules(\Lomkit\Rest\Http\Resource $resource, strin
251251
*/
252252
protected function sortsRules(\Lomkit\Rest\Http\Resource $resource, string $prefix)
253253
{
254+
$fields = $this->isScoutMode() ?
255+
Rule::in($resource->getScoutFields($this->request)):
256+
Rule::in($resource->getFields($this->request));
257+
254258
$rules = [
255259
$prefix.'.*.field' => [
256-
Rule::in($resource->getFields($this->request)),
260+
$fields,
257261
'required',
258262
'string',
259263
],

tests/Feature/Controllers/SearchScoutOperationsTest.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,31 @@ public function test_getting_a_list_of_resources_with_not_allowed_filter_field()
9191
$response->assertJsonStructure(['message', 'errors' => ['search.filters.0.field']]);
9292
}
9393

94+
public function test_getting_a_list_of_resources_with_not_allowed_sort_field(): void
95+
{
96+
ModelFactory::new()->count(2)->create();
97+
98+
Gate::policy(Model::class, GreenPolicy::class);
99+
100+
$response = $this->post(
101+
'/api/searchable-models/search',
102+
[
103+
'search' => [
104+
'text' => [
105+
'value' => 'text',
106+
],
107+
'sorts' => [
108+
['field' => 'id'],
109+
],
110+
],
111+
],
112+
['Accept' => 'application/json']
113+
);
114+
115+
$response->assertStatus(422);
116+
$response->assertJsonStructure(['message', 'errors' => ['search.sorts.0.field']]);
117+
}
118+
94119
public function test_getting_a_list_of_resources_with_allowed_filter_field(): void
95120
{
96121
ModelFactory::new()->count(2)->create();
@@ -119,6 +144,34 @@ public function test_getting_a_list_of_resources_with_allowed_filter_field(): vo
119144
);
120145
}
121146

147+
public function test_getting_a_list_of_resources_with_allowed_sort_field(): void
148+
{
149+
ModelFactory::new()->count(2)->create();
150+
151+
Gate::policy(Model::class, GreenPolicy::class);
152+
153+
$response = $this->post(
154+
'/api/searchable-models/search',
155+
[
156+
'search' => [
157+
'text' => [
158+
'value' => 'text',
159+
],
160+
'sorts' => [
161+
['field' => 'allowed_scout_field'],
162+
],
163+
],
164+
],
165+
['Accept' => 'application/json']
166+
);
167+
168+
$this->assertResourcePaginated(
169+
$response,
170+
[],
171+
new ModelResource()
172+
);
173+
}
174+
122175
public function test_getting_a_list_of_resources_with_not_allowed_filter_nested(): void
123176
{
124177
ModelFactory::new()->count(2)->create();

tests/Unit/LaravelScoutTest.php

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<?php
2+
3+
use Illuminate\Support\Facades\Auth;
4+
use Illuminate\Support\Facades\Gate;
5+
use Lomkit\Rest\Contracts\QueryBuilder;
6+
use Lomkit\Rest\Query\Builder;
7+
use Lomkit\Rest\Query\ScoutBuilder;
8+
use Lomkit\Rest\Tests\Support\Models\Model;
9+
use Lomkit\Rest\Tests\Support\Models\User;
10+
use Lomkit\Rest\Tests\Support\Policies\GreenPolicy;
11+
use Lomkit\Rest\Tests\Support\Rest\Resources\ModelResource;
12+
use Lomkit\Rest\Tests\Support\Rest\Resources\SearchableModelResource;
13+
use Mockery\MockInterface;
14+
15+
class LaravelScoutTest extends \Lomkit\Rest\Tests\TestCase
16+
{
17+
public function test_building_scout_query()
18+
{
19+
Auth::setUser(Mockery::mock(User::class));
20+
Gate::policy(Model::class, GreenPolicy::class);
21+
22+
$scoutQueryBuilderMock = Mockery::mock(ScoutBuilder::class, [new SearchableModelResource])->makePartial();
23+
24+
$scoutQueryBuilderMock->shouldReceive('applyFilters')->with([])->never();
25+
$scoutQueryBuilderMock->shouldReceive('applySorts')->with([])->never();
26+
$scoutQueryBuilderMock->shouldReceive('applyInstructions')->with([])->never();
27+
28+
$scoutQueryBuilderMock
29+
->search([
30+
'text' => [
31+
'value' => 'my specific search',
32+
],
33+
]);
34+
35+
$this->assertEquals('my specific search', $scoutQueryBuilderMock->toBase()->query);
36+
}
37+
38+
public function test_building_scout_with_filters()
39+
{
40+
Auth::setUser(Mockery::mock(User::class));
41+
Gate::policy(Model::class, GreenPolicy::class);
42+
43+
$scoutQueryBuilderMock = Mockery::mock(ScoutBuilder::class, [new SearchableModelResource])->makePartial();
44+
45+
$scoutQueryBuilderMock->shouldReceive('applyFilters')->with([['field' => 'test', 'value' => 1]])->once();
46+
$scoutQueryBuilderMock->shouldReceive('applySorts')->with([])->never();
47+
$scoutQueryBuilderMock->shouldReceive('applyInstructions')->with([])->never();
48+
49+
$scoutQueryBuilderMock
50+
->search([
51+
'text' => [
52+
['value' => 'test'],
53+
],
54+
'filters' => [
55+
['field' => 'test', 'value' => 1]
56+
]
57+
]);
58+
}
59+
60+
public function test_building_scout_with_sorts()
61+
{
62+
Auth::setUser(Mockery::mock(User::class));
63+
Gate::policy(Model::class, GreenPolicy::class);
64+
65+
$scoutQueryBuilderMock = Mockery::mock(ScoutBuilder::class, [new SearchableModelResource])->makePartial();
66+
67+
$scoutQueryBuilderMock->shouldReceive('applyFilters')->with([])->never();
68+
$scoutQueryBuilderMock->shouldReceive('applySorts')->with([['field' => 'id']])->once();
69+
$scoutQueryBuilderMock->shouldReceive('applyInstructions')->with([])->never();
70+
71+
$scoutQueryBuilderMock
72+
->search([
73+
'text' => [
74+
['value' => 'test'],
75+
],
76+
'sorts' => [
77+
['field' => 'id'],
78+
]
79+
]);
80+
}
81+
82+
public function test_building_scout_with_instructions()
83+
{
84+
Auth::setUser(Mockery::mock(User::class));
85+
Gate::policy(Model::class, GreenPolicy::class);
86+
87+
$scoutQueryBuilderMock = Mockery::mock(ScoutBuilder::class, [new SearchableModelResource])->makePartial();
88+
89+
$scoutQueryBuilderMock->shouldReceive('applyFilters')->with([])->never();
90+
$scoutQueryBuilderMock->shouldReceive('applySorts')->with([])->never();
91+
$scoutQueryBuilderMock->shouldReceive('applyInstructions')->with([['name' => 'my_instruction']])->once();
92+
93+
$scoutQueryBuilderMock
94+
->search([
95+
'text' => [
96+
['value' => 'test'],
97+
],
98+
'instructions' => [
99+
['name' => 'my_instruction'],
100+
],
101+
]);
102+
103+
($scoutQueryBuilderMock->toBase()->queryCallback)(Model::query());
104+
}
105+
}

tests/Unit/LaravelScoutTests.php

Lines changed: 0 additions & 51 deletions
This file was deleted.

0 commit comments

Comments
 (0)