Skip to content

Commit 477fba4

Browse files
authored
Merge pull request #3 from olekjs/release-v1.2.0-dev
Release v1.2.0 dev
2 parents 6cce7a1 + 7bc2905 commit 477fba4

22 files changed

+912
-21
lines changed

src/Builder/Builder.php

Lines changed: 133 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,18 @@
55
use Illuminate\Support\Traits\Conditionable;
66
use LogicException;
77
use Olekjs\Elasticsearch\Client;
8+
use Olekjs\Elasticsearch\Contracts\BuilderInterface;
89
use Olekjs\Elasticsearch\Contracts\ClientInterface;
10+
use Olekjs\Elasticsearch\Dto\FindResponseDto;
11+
use Olekjs\Elasticsearch\Dto\PaginateResponseDto;
912
use Olekjs\Elasticsearch\Dto\SearchResponseDto;
13+
use Olekjs\Elasticsearch\Exceptions\CoreException;
14+
use Olekjs\Elasticsearch\Exceptions\FindResponseException;
15+
use Olekjs\Elasticsearch\Exceptions\IndexNotFoundResponseException;
16+
use Olekjs\Elasticsearch\Exceptions\NotFoundResponseException;
17+
use Olekjs\Elasticsearch\Exceptions\SearchResponseException;
1018

11-
class Builder
19+
class Builder implements BuilderInterface
1220
{
1321
use Conditionable;
1422

@@ -45,20 +53,70 @@ public function where(string $field, string $value): self
4553
return $this;
4654
}
4755

56+
public function orWhere(string $field, string $value): self
57+
{
58+
$this->query['bool']['should'][]['term'][$field . '.keyword'] = $value;
59+
60+
return $this;
61+
}
62+
4863
public function whereLike(string $field, string|int|float|array $value): self
4964
{
5065
$this->query['bool']['filter'][]['term'][$field] = $value;
5166

5267
return $this;
5368
}
5469

70+
public function orWhereLike(string $field, string|int|float|array $value): self
71+
{
72+
$this->query['bool']['should'][]['term'][$field] = $value;
73+
74+
return $this;
75+
}
76+
5577
public function whereIn(string $field, array $values): self
5678
{
5779
$this->query['bool']['filter'][]['terms'][$field] = $values;
5880

5981
return $this;
6082
}
6183

84+
public function orWhereIn(string $field, array $values): self
85+
{
86+
$this->query['bool']['should'][]['terms'][$field] = $values;
87+
88+
return $this;
89+
}
90+
91+
public function whereGreaterThan(string $field, int|float $value): self
92+
{
93+
return $this->whereRange($field, $value, 'gt');
94+
}
95+
96+
public function whereLessThan(string $field, int|float $value): self
97+
{
98+
return $this->whereRange($field, $value, 'lt');
99+
}
100+
101+
public function whereBetween(string $field, array $values): self
102+
{
103+
if (!isset($values[0], $values[1])) {
104+
throw new LogicException('Provide two values');
105+
}
106+
107+
$this->whereRange($field, $values[0], 'gte');
108+
$this->whereRange($field, $values[1], 'lte');
109+
110+
return $this;
111+
}
112+
113+
public function whereRange(string $field, int|float $value, string $operator): self
114+
{
115+
$this->query['bool']['filter'][]['range'][$field][$operator] = $value;
116+
117+
return $this;
118+
}
119+
62120
public function offset(int $offset): self
63121
{
64122
$this->body['from'] = $offset;
@@ -73,25 +131,79 @@ public function limit(int $limit): self
73131
return $this;
74132
}
75133

76-
public function get(): SearchResponseDto
134+
/**
135+
* @throws IndexNotFoundResponseException
136+
* @throws FindResponseException
137+
*/
138+
public function find(int|string $id): ?FindResponseDto
77139
{
78140
if (!isset($this->index)) {
79141
throw new LogicException('Index name is required.');
80142
}
81143

82-
if (isset($this->query)) {
83-
$this->body['query'] = $this->query;
144+
return $this->client->find($this->index, $id);
145+
}
146+
147+
/**
148+
* @throws IndexNotFoundResponseException
149+
* @throws NotFoundResponseException
150+
* @throws FindResponseException
151+
*/
152+
public function findOrFail(int|string $id): FindResponseDto
153+
{
154+
if (!isset($this->index)) {
155+
throw new LogicException('Index name is required.');
84156
}
85157

86-
if (empty($this->body)) {
87-
$this->body['query'] = [
88-
'match_all' => (object)[]
89-
];
158+
return $this->client->findOrFail($this->index, $id);
159+
}
160+
161+
/**
162+
* @throws SearchResponseException
163+
* @throws CoreException
164+
*/
165+
public function count(): int
166+
{
167+
if (!isset($this->index)) {
168+
throw new LogicException('Index name is required.');
169+
}
170+
171+
$this->performSearchBody();
172+
173+
unset($this->body['size']);
174+
175+
return $this->client->count($this->index, $this->body);
176+
}
177+
178+
/**
179+
* @throws SearchResponseException
180+
*/
181+
public function get(): SearchResponseDto
182+
{
183+
if (!isset($this->index)) {
184+
throw new LogicException('Index name is required.');
90185
}
91186

187+
$this->performSearchBody();
188+
92189
return $this->client->search($this->index, $this->body);
93190
}
94191

192+
/**
193+
* @throws SearchResponseException
194+
* @throws CoreException
195+
*/
196+
public function paginate(int $page = 1, int $perPage = 25): PaginateResponseDto
197+
{
198+
if (!isset($this->index)) {
199+
throw new LogicException('Index name is required.');
200+
}
201+
202+
$this->performSearchBody();
203+
204+
return $this->client->paginate($this->index, $this->body, $page, $perPage);
205+
}
206+
95207
public function getIndex(): string
96208
{
97209
return $this->index;
@@ -106,4 +218,17 @@ public function getQuery(): array
106218
{
107219
return $this->query;
108220
}
221+
222+
private function performSearchBody(): void
223+
{
224+
if (isset($this->query)) {
225+
$this->body['query'] = $this->query;
226+
}
227+
228+
if (empty($this->body)) {
229+
$this->body['query'] = [
230+
'match_all' => (object)[]
231+
];
232+
}
233+
}
109234
}

src/Client.php

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
use Olekjs\Elasticsearch\Contracts\AbstractClient;
66
use Olekjs\Elasticsearch\Contracts\ClientInterface;
77
use Olekjs\Elasticsearch\Dto\IndexResponseDto;
8+
use Olekjs\Elasticsearch\Dto\PaginateResponseDto;
89
use Olekjs\Elasticsearch\Dto\SearchResponseDto;
910
use Olekjs\Elasticsearch\Exceptions\ConflictResponseException;
11+
use Olekjs\Elasticsearch\Exceptions\CoreException;
1012
use Olekjs\Elasticsearch\Exceptions\DeleteResponseException;
1113
use Olekjs\Elasticsearch\Exceptions\FindResponseException;
1214
use Olekjs\Elasticsearch\Exceptions\IndexNotFoundResponseException;
@@ -16,6 +18,7 @@
1618
use Olekjs\Elasticsearch\Exceptions\UpdateResponseException;
1719
use Olekjs\Elasticsearch\Utils\FindResponse;
1820
use Olekjs\Elasticsearch\Utils\IndexResponse;
21+
use Olekjs\Elasticsearch\Utils\PaginateResponse;
1922
use Olekjs\Elasticsearch\Utils\SearchResponse;
2023
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
2124
use Olekjs\Elasticsearch\Dto\FindResponseDto;
@@ -241,7 +244,7 @@ public function searchWhereLike(string $index, string $field, string|int|float $
241244
public function increment(string $index, string|int $id, string $field, int $value = 1): IndexResponseDto
242245
{
243246
return $this->update($index, $id, [], [
244-
'source' => "ctx._source.doc.$field += params.count",
247+
'source' => "ctx._source.$field += params.count",
245248
'params' => [
246249
'count' => $value
247250
]
@@ -256,10 +259,82 @@ public function increment(string $index, string|int $id, string $field, int $val
256259
public function decrement(string $index, string|int $id, string $field, int $value = 1): IndexResponseDto
257260
{
258261
return $this->update($index, $id, [], [
259-
'source' => "ctx._source.doc.$field -= params.count",
262+
'source' => "ctx._source.$field -= params.count",
260263
'params' => [
261264
'count' => $value
262265
]
263266
]);
264267
}
268+
269+
/**
270+
* @throws SearchResponseException
271+
* @throws CoreException
272+
*/
273+
public function count(string $index, array $data = []): int
274+
{
275+
if (empty($data)) {
276+
$data = [
277+
'query' => [
278+
'match_all' => (object)[]
279+
]
280+
];
281+
}
282+
283+
$response = $this->getBaseClient()
284+
->post("$index/_count", $data);
285+
286+
if ($response->clientError()) {
287+
$this->throwSearchResponseException(
288+
data_get($response, 'error.reason'),
289+
$response->status(),
290+
);
291+
}
292+
293+
return data_get(
294+
$response,
295+
'count',
296+
fn() => throw new CoreException('Wrong response type')
297+
);
298+
}
299+
300+
/**
301+
* @throws SearchResponseException
302+
* @throws CoreException
303+
*/
304+
public function paginate(string $index, array $data = [], int $page = 1, int $perPage = 25): PaginateResponseDto
305+
{
306+
if (empty($data)) {
307+
$data = [
308+
'query' => [
309+
'match_all' => (object)[]
310+
]
311+
];
312+
}
313+
314+
$totalDocuments = $this->count($index, $data);
315+
316+
$pages = (int)ceil(
317+
$totalDocuments === 0 ? 0 : ($totalDocuments <= $perPage ? 1 : $totalDocuments / $perPage)
318+
);
319+
320+
$data['from'] = $page * $perPage;
321+
$data['size'] = $perPage;
322+
323+
$response = $this->getBaseClient()
324+
->post("$index/_search", $data);
325+
326+
if ($response->clientError()) {
327+
$this->throwSearchResponseException(
328+
data_get($response, 'error.reason'),
329+
$response->status(),
330+
);
331+
}
332+
333+
return PaginateResponse::from($response, [
334+
'per_page' => $perPage,
335+
'current_page' => $page,
336+
'total_pages' => $pages,
337+
'total_documents' => $totalDocuments
338+
]);
339+
}
265340
}

src/Contracts/BuilderInterface.php

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
namespace Olekjs\Elasticsearch\Contracts;
4+
5+
use Olekjs\Elasticsearch\Builder\Builder;
6+
use Olekjs\Elasticsearch\Dto\FindResponseDto;
7+
use Olekjs\Elasticsearch\Dto\PaginateResponseDto;
8+
use Olekjs\Elasticsearch\Dto\SearchResponseDto;
9+
use Olekjs\Elasticsearch\Exceptions\CoreException;
10+
use Olekjs\Elasticsearch\Exceptions\FindResponseException;
11+
use Olekjs\Elasticsearch\Exceptions\IndexNotFoundResponseException;
12+
use Olekjs\Elasticsearch\Exceptions\NotFoundResponseException;
13+
use Olekjs\Elasticsearch\Exceptions\SearchResponseException;
14+
15+
interface BuilderInterface
16+
{
17+
public static function query(?ClientInterface $client = null): Builder;
18+
19+
public function index(string $index): self;
20+
21+
public function where(string $field, string $value): self;
22+
23+
public function orWhere(string $field, string $value): self;
24+
25+
public function whereLike(string $field, string|int|float|array $value): self;
26+
27+
public function orWhereLike(string $field, string|int|float|array $value): self;
28+
29+
public function whereIn(string $field, array $values): self;
30+
31+
public function orWhereIn(string $field, array $values): self;
32+
33+
public function whereGreaterThan(string $field, int|float $value): self;
34+
35+
public function whereLessThan(string $field, int|float $value): self;
36+
37+
public function whereBetween(string $field, array $values): self;
38+
39+
public function whereRange(string $field, int|float $value, string $operator): self;
40+
41+
public function offset(int $offset): self;
42+
43+
public function limit(int $limit): self;
44+
45+
/**
46+
* @throws IndexNotFoundResponseException
47+
* @throws FindResponseException
48+
*/
49+
public function find(int|string $id): ?FindResponseDto;
50+
51+
/**
52+
* @throws IndexNotFoundResponseException
53+
* @throws NotFoundResponseException
54+
* @throws FindResponseException
55+
*/
56+
public function findOrFail(int|string $id): FindResponseDto;
57+
58+
/**
59+
* @throws SearchResponseException
60+
* @throws CoreException
61+
*/
62+
public function count(): int;
63+
64+
/**
65+
* @throws SearchResponseException
66+
*/
67+
public function get(): SearchResponseDto;
68+
69+
/**
70+
* @throws SearchResponseException
71+
* @throws CoreException
72+
*/
73+
public function paginate(int $page = 1, int $perPage = 25): PaginateResponseDto;
74+
75+
public function getIndex(): string;
76+
77+
public function getBody(): array;
78+
79+
public function getQuery(): array;
80+
}

0 commit comments

Comments
 (0)