Skip to content

Commit 95d2719

Browse files
committed
feat: Enhance Elasticsearch query builder with result type and document class support
1 parent 00a3fdb commit 95d2719

File tree

1 file changed

+85
-33
lines changed

1 file changed

+85
-33
lines changed

src/Query/Builder.php

+85-33
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,16 @@ class Builder
9494
*/
9595
protected array $with = [];
9696

97+
/**
98+
* The result type for the query.
99+
*/
100+
protected ?string $resultType = null;
101+
102+
/**
103+
* The document class for custom document DTOs.
104+
*/
105+
protected ?string $documentClass = null;
106+
97107
/**
98108
* Create a new Elasticsearch query builder instance.
99109
*/
@@ -117,6 +127,25 @@ public function setModel(string $model): self
117127
return $this;
118128
}
119129

130+
/**
131+
* Set the result type to document.
132+
*/
133+
public function asDocument(): self
134+
{
135+
$this->resultType = 'document';
136+
return $this;
137+
}
138+
139+
/**
140+
* Set the result type to use a custom document DTO class.
141+
*/
142+
public function asData(string $documentClass): self
143+
{
144+
$this->resultType = 'document';
145+
$this->documentClass = $documentClass;
146+
return $this;
147+
}
148+
120149
/**
121150
* Add a basic where clause to the query.
122151
*/
@@ -555,42 +584,14 @@ public function first()
555584
*/
556585
public function get(): Collection
557586
{
558-
$params = $this->buildParams();
559-
$result = [];
560-
561-
// Use ES|QL endpoint if esqlQuery is set
562-
if ($this->esqlQuery !== null) {
563-
$result = $this->elasticManager->esql(
564-
$params['esql'],
565-
[
566-
'from' => $this->from,
567-
'size' => $this->size,
568-
]
569-
);
570-
} else {
571-
$result = $this->elasticManager->search(
572-
$this->model::getIndexName(),
573-
$params,
574-
[
575-
'from' => $this->from,
576-
'size' => $this->size,
577-
'sort' => $this->sort,
578-
]
579-
);
580-
}
581-
582-
$collection = new Collection();
583-
584-
foreach ($result['hits'] as $hit) {
585-
$data = $hit['_source'] ?? [];
586-
$data['_id'] = $hit['_id'];
587-
$data['_score'] = $hit['_score'] ?? null;
587+
$params = $this->buildQuery();
588+
$response = $this->elasticManager->getClient()->search($params);
588589

589-
$model = $this->model::newFromElasticData($data);
590-
$collection->push($model);
590+
if ($this->resultType === 'document') {
591+
return new Collection($response['hits']['hits']);
591592
}
592593

593-
return $collection;
594+
return $this->hydrate($response->asArray());
594595
}
595596

596597
/**
@@ -1717,4 +1718,55 @@ public function whereDoesntHave(string $relation): self
17171718

17181719
return $this;
17191720
}
1721+
1722+
/**
1723+
* Build the Elasticsearch query parameters.
1724+
*/
1725+
protected function buildQuery(): array
1726+
{
1727+
$params = [
1728+
'index' => $this->model::getIndexName(),
1729+
'body' => [
1730+
'query' => $this->query,
1731+
],
1732+
];
1733+
1734+
if ($this->from !== null) {
1735+
$params['from'] = $this->from;
1736+
}
1737+
1738+
if ($this->size !== null) {
1739+
$params['size'] = $this->size;
1740+
}
1741+
1742+
if (!empty($this->sort)) {
1743+
$params['sort'] = $this->sort;
1744+
}
1745+
1746+
return $params;
1747+
}
1748+
1749+
/**
1750+
* Hydrate the search results into model instances.
1751+
*/
1752+
protected function hydrate(array $response): Collection
1753+
{
1754+
$collection = new Collection();
1755+
1756+
foreach ($response['hits']['hits'] as $hit) {
1757+
$data = $hit['_source'] ?? [];
1758+
$data['_id'] = $hit['_id'];
1759+
$data['_score'] = $hit['_score'] ?? null;
1760+
1761+
if ($this->documentClass) {
1762+
$model = new $this->documentClass($data);
1763+
} else {
1764+
$model = $this->model::newFromElasticData($data);
1765+
}
1766+
1767+
$collection->push($model);
1768+
}
1769+
1770+
return $collection;
1771+
}
17201772
}

0 commit comments

Comments
 (0)