Skip to content

Commit 7fd1166

Browse files
committed
Add typed search request payload
1 parent 2fde08d commit 7fd1166

5 files changed

Lines changed: 305 additions & 171 deletions

File tree

src/Factories/SearchRequestFactory.php

Lines changed: 21 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
use DirectoryTree\OpenSearchAdapter\Search\SearchRequest as OpenSearchRequest;
66
use DirectoryTree\OpenSearchScoutDriver\SearchRequest;
7-
use Illuminate\Contracts\Support\Arrayable;
7+
use DirectoryTree\OpenSearchScoutDriver\SearchRequestPayload;
8+
use DirectoryTree\OpenSearchScoutDriver\SearchRequestPayloadInterface;
89
use Laravel\Scout\Builder;
9-
use stdClass;
1010

1111
/**
1212
* Creates OpenSearch search requests from Scout builders.
@@ -20,78 +20,41 @@ class SearchRequestFactory implements SearchRequestFactoryInterface
2020
*/
2121
public function makeFromBuilder(Builder $builder, array $options = []): SearchRequest
2222
{
23-
if ($compiled = $this->compileBuilder($builder, $options)) {
24-
return $this->makeFromCompiled($builder, $compiled);
25-
}
26-
27-
$request = new OpenSearchRequest($this->makeQuery($builder));
28-
29-
if ($sort = $this->makeSort($builder)) {
30-
$request->sort($sort);
31-
}
32-
33-
if (! is_null($from = $this->makeFrom($options))) {
34-
$request->from($from);
35-
}
36-
37-
if (! is_null($size = $this->makeSize($builder, $options))) {
38-
$request->size($size);
39-
}
23+
$payload = $builder instanceof SearchRequestPayloadInterface
24+
? $builder->toSearchRequestPayload($options)
25+
: SearchRequestPayload::fromBuilder($builder, $options);
4026

41-
$this->applyOptions($request, $builder->options);
42-
43-
return new SearchRequest($this->makeIndex($builder), $request);
27+
return $this->makeFromPayload($builder, $payload);
4428
}
4529

4630
/**
47-
* Make an OpenSearch request from a compiled builder payload.
48-
*
49-
* @param array{query?: array<string, mixed>|null, sort?: array<int|string, mixed>|null, from?: int|null, size?: int|string|null, aggs?: array<string, mixed>|null, aggregations?: array<string, mixed>|null} $compiled
31+
* Make an OpenSearch request from a builder payload.
5032
*/
51-
protected function makeFromCompiled(Builder $builder, array $compiled): SearchRequest
33+
protected function makeFromPayload(Builder $builder, SearchRequestPayload $payload): SearchRequest
5234
{
53-
$request = new OpenSearchRequest($compiled['query'] ?? []);
54-
55-
if (! empty($compiled['sort'])) {
56-
$request->sort($compiled['sort']);
57-
}
35+
$request = new OpenSearchRequest($payload->query());
5836

59-
if (! empty($compiled['from'])) {
60-
$request->from((int) $compiled['from']);
37+
if ($sort = $payload->sort()) {
38+
$request->sort($sort);
6139
}
6240

63-
if (isset($compiled['size']) && is_numeric($compiled['size'])) {
64-
$request->size((int) $compiled['size']);
41+
if (! is_null($from = $payload->from())) {
42+
$request->from($from);
6543
}
6644

67-
if (! empty($compiled['aggs'])) {
68-
$request->aggregations($compiled['aggs']);
45+
if (! is_null($size = $payload->size())) {
46+
$request->size($size);
6947
}
7048

71-
if (! empty($compiled['aggregations'])) {
72-
$request->aggregations($compiled['aggregations']);
49+
if ($aggregations = $payload->aggregations()) {
50+
$request->aggregations($aggregations);
7351
}
7452

7553
$this->applyOptions($request, $builder->options);
7654

7755
return new SearchRequest($this->makeIndex($builder), $request);
7856
}
7957

80-
/**
81-
* Compile builders that expose their own OpenSearch payload.
82-
*
83-
* @param array<string, mixed> $options
84-
* @return array<string, mixed>|null
85-
*/
86-
protected function compileBuilder(Builder $builder, array $options): ?array
87-
{
88-
if (! $builder instanceof Arrayable) {
89-
return null;
90-
}
91-
92-
return $builder->toArray($options);
93-
}
94-
9558
/**
9659
* Get the OpenSearch index name for the builder.
9760
*/
@@ -100,106 +63,6 @@ protected function makeIndex(Builder $builder): string
10063
return $builder->index ?: $builder->model->searchableAs();
10164
}
10265

103-
/**
104-
* Create the OpenSearch query body.
105-
*
106-
* @return array<string, mixed>
107-
*/
108-
protected function makeQuery(Builder $builder): array
109-
{
110-
$query = [
111-
'bool' => [],
112-
];
113-
114-
if (! empty($builder->query)) {
115-
$query['bool']['must'] = [
116-
'query_string' => [
117-
'query' => $builder->query,
118-
],
119-
];
120-
} else {
121-
$query['bool']['must'] = [
122-
'match_all' => new stdClass,
123-
];
124-
}
125-
126-
if ($filter = $this->makeFilter($builder)) {
127-
$query['bool']['filter'] = $filter;
128-
}
129-
130-
return $query;
131-
}
132-
133-
/**
134-
* Create the OpenSearch filter clauses.
135-
*
136-
* @return array<int, array<string, mixed>>|null
137-
*/
138-
protected function makeFilter(Builder $builder): ?array
139-
{
140-
$filter = [];
141-
142-
foreach ($builder->wheres as $field => $value) {
143-
if (is_array($value) && isset($value['field'], $value['value'])) {
144-
$filter[] = ['term' => [$value['field'] => $value['value']]];
145-
146-
continue;
147-
}
148-
149-
$filter[] = ['term' => [$field => $value]];
150-
}
151-
152-
if (property_exists($builder, 'whereIns')) {
153-
foreach ($builder->whereIns as $field => $values) {
154-
$filter[] = ['terms' => [$field => $values]];
155-
}
156-
}
157-
158-
return empty($filter) ? null : $filter;
159-
}
160-
161-
/**
162-
* Create the OpenSearch sort clauses.
163-
*
164-
* @return array<int, array<string, string>>|null
165-
*/
166-
protected function makeSort(Builder $builder): ?array
167-
{
168-
$sort = [];
169-
170-
foreach ($builder->orders as $order) {
171-
$sort[] = [$order['column'] => $order['direction']];
172-
}
173-
174-
return empty($sort) ? null : $sort;
175-
}
176-
177-
/**
178-
* Create the OpenSearch result offset.
179-
*
180-
* @param array{page?: int, perPage?: int} $options
181-
*/
182-
protected function makeFrom(array $options): ?int
183-
{
184-
if (isset($options['page'], $options['perPage'])) {
185-
return ($options['page'] - 1) * $options['perPage'];
186-
}
187-
188-
return null;
189-
}
190-
191-
/**
192-
* Create the OpenSearch result size.
193-
*
194-
* @param array{perPage?: int} $options
195-
*/
196-
protected function makeSize(Builder $builder, array $options): ?int
197-
{
198-
$size = $options['perPage'] ?? $builder->limit;
199-
200-
return is_numeric($size) ? (int) $size : null;
201-
}
202-
20366
/**
20467
* Apply Scout builder options to the OpenSearch search request.
20568
*
@@ -255,12 +118,12 @@ protected function applyOptions(OpenSearchRequest $request, array $options): voi
255118
$request->source($options['_source']);
256119
}
257120

258-
if (array_key_exists('track_total_hits', $options)) {
259-
$request->trackTotalHits($options['track_total_hits']);
260-
}
261-
262121
if (array_key_exists('track_scores', $options)) {
263122
$request->trackScores($options['track_scores']);
264123
}
124+
125+
if (array_key_exists('track_total_hits', $options)) {
126+
$request->trackTotalHits($options['track_total_hits']);
127+
}
265128
}
266129
}

0 commit comments

Comments
 (0)