Skip to content

Commit d454e42

Browse files
CorentinCousseCorentin COUSSEGautierDele
authored
Fix scout paginate total count by reordering query callback applyiance (#200)
--------- Co-authored-by: Corentin COUSSE <c.cousse@xefi.fr> Co-authored-by: Gautier DELEGLISE <gautier.deleglise@gmail.com>
1 parent bff8127 commit d454e42

File tree

3 files changed

+45
-25
lines changed

3 files changed

+45
-25
lines changed

src/Concerns/Resource/Paginable.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Laravel\Scout\Builder;
66
use Lomkit\Rest\Http\Requests\RestRequest;
7+
use Lomkit\Rest\Query\ScoutBuilder;
78

89
trait Paginable
910
{
@@ -21,7 +22,19 @@ public function paginate($query, RestRequest $request)
2122

2223
// In case we have a scout builder
2324
if ($query instanceof Builder) {
24-
return $query->paginate($request->input('search.limit', $defaultLimit), 'page', $request->input('search.page', 1));
25+
$paginator = $query->paginate($request->input('search.limit', $defaultLimit), 'page', $request->input('search.page', 1));
26+
27+
if ($paginator->isEmpty()) {
28+
return $paginator;
29+
}
30+
31+
$paginatedQuery = $paginator->getCollection()->toQuery();
32+
// Apply query callback after pagination to prevent Scout from mapping all IDs during total count calculation,
33+
// which can cause "allowed memory size" errors with large result sets
34+
$scoutBuilder = (new ScoutBuilder($this))->applyQueryCallback($paginatedQuery, $request->input('search', []));
35+
$results = $scoutBuilder->get();
36+
37+
return $paginator->setCollection($results);
2538
}
2639

2740
return $query->paginate($request->input('search.limit', $defaultLimit), ['*'], 'page', $request->input('search.page', 1));

src/Query/ScoutBuilder.php

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@ class ScoutBuilder implements QueryBuilder
1818
* This method configures the underlying search builder by setting the query text,
1919
* and conditionally applying filters, sort orders, and additional instructions based
2020
* on the provided parameters. It also enforces a limit on the number of results,
21-
* defaulting to 50 if no limit is specified. Any extra parameters, after excluding
22-
* reserved keys (filters, instructions, sorts, text, and limit), are forwarded to the
23-
* underlying search operation.
21+
* defaulting to 50 if no limit is specified.
2422
*
2523
* @param array $parameters An associative array of search criteria, which may include:
2624
* - 'text': An array containing 'value' (search string) and optionally 'trashed' ('with'|'only').
@@ -53,27 +51,36 @@ public function search(array $parameters = [])
5351
$this->applyInstructions($parameters['instructions']);
5452
});
5553

56-
$this->queryBuilder
57-
->query(function (Builder $query) use ($parameters) {
58-
app()->make(QueryBuilder::class, ['query' => $query, 'resource' => $this->resource])
59-
->disableSecurity()
60-
->search(
61-
collect($parameters)
62-
->except([
63-
'filters',
64-
'instructions',
65-
'sorts',
66-
'text',
67-
'limit',
68-
'page',
69-
])
70-
->all()
71-
);
72-
});
73-
7454
return $this->queryBuilder;
7555
}
7656

57+
/**
58+
* Forwards the extra parameters after excluding reserved keys (filters, instructions, sorts, text, and limit)
59+
* to the underlying search operation.
60+
*
61+
* @param \Laravel\Scout\Builder $query
62+
* @param array $parameters
63+
*
64+
* @return \Laravel\Scout\Builder The new query builder.
65+
*/
66+
public function applyQueryCallback($query, $parameters)
67+
{
68+
return app()->make(QueryBuilder::class, ['query' => $query, 'resource' => $this->resource])
69+
->disableSecurity()
70+
->search(
71+
collect($parameters)
72+
->except([
73+
'filters',
74+
'instructions',
75+
'sorts',
76+
'text',
77+
'limit',
78+
'page',
79+
])
80+
->all()
81+
);
82+
}
83+
7784
/**
7885
* Apply multiple filters to the query builder.
7986
*

tests/Unit/LaravelScoutTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public function test_building_scout_with_instructions()
9393
],
9494
]);
9595

96-
($scoutQueryBuilderMock->toBase()->queryCallback)(Model::query());
96+
$this->assertNull($scoutQueryBuilderMock->toBase()->queryCallback);
9797
}
9898

9999
public function test_building_scout_with_trashed()
@@ -116,7 +116,7 @@ public function test_building_scout_with_trashed()
116116
],
117117
]);
118118

119-
($scoutQueryBuilderMock->toBase()->queryCallback)(Model::query());
119+
$this->assertNull($scoutQueryBuilderMock->toBase()->queryCallback);
120120
}
121121

122122
public function test_building_scout_only_trashed()
@@ -139,6 +139,6 @@ public function test_building_scout_only_trashed()
139139
],
140140
]);
141141

142-
($scoutQueryBuilderMock->toBase()->queryCallback)(Model::query());
142+
$this->assertNull($scoutQueryBuilderMock->toBase()->queryCallback);
143143
}
144144
}

0 commit comments

Comments
 (0)