diff --git a/src/Alias/Alias.php b/src/Alias/Alias.php new file mode 100644 index 0000000..5540597 --- /dev/null +++ b/src/Alias/Alias.php @@ -0,0 +1,110 @@ +client->getBaseClient()->get("$alias/_alias"); + + if ($response->clientError()) { + $this->client->throwSearchResponseException( + data_get($response, 'error.reason'), + $response->status(), + ); + } + + $indices = []; + foreach ($response->json() as $index => $aliases) { + $indices[] = $index; + } + + return $indices; + } + + public function add(string $index, string $alias): bool + { + $response = $this->runActions([ + [ + 'add' => [ + 'index' => $index, + 'alias' => $alias, + ] + ] + ]); + + return $response->successful(); + } + + public function remove(string $index, string $alias): bool + { + $response = $this->runActions([ + [ + 'remove' => [ + 'index' => $index, + 'alias' => $alias, + ] + ] + ]); + + return $response->successful(); + } + + public function runActions(array $actions): Response + { + $response = $this->client->getBaseClient()->post('_aliases', ['actions' => $actions]); + + if ($response->clientError()) { + $this->client->throwUpdateResponseException( + json_encode($response->json(), JSON_THROW_ON_ERROR), + $response->status() + ); + } + + return $response; + } + + public function replace(string $alias, string $newIndex, ?string $oldIndex = null): bool + { + if (null === $oldIndex) { + $indices = $this->getIndicesForAlias($alias); + + $oldIndex = $indices[0] ?? null; + } + + if (null === $oldIndex) { + throw new \LogicException('Old index is not defined.'); + } + + $response = $this->runActions([ + [ + 'add' => [ + 'index' => $newIndex, + 'alias' => $alias, + ] + ], + [ + 'remove' => [ + 'index' => $oldIndex, + 'alias' => $alias, + ] + ] + ]); + + return $response->successful(); + } +} \ No newline at end of file diff --git a/src/Client.php b/src/Client.php index cc89e9e..552a469 100644 --- a/src/Client.php +++ b/src/Client.php @@ -103,7 +103,7 @@ public function create(string $index, string|int $id, array $data): IndexRespons if ($response->clientError()) { $this->throwIndexResponseException( - json_encode($response->json()), + json_encode($response->json(), JSON_THROW_ON_ERROR), $response->status() ); } @@ -132,7 +132,7 @@ public function update( 'if_seq_no' => $sequenceNumber, ]); - $baseUrl = $baseUrl . '?' . $strictUrl; + $baseUrl .= '?' . $strictUrl; } $body = match (true) { @@ -145,7 +145,7 @@ public function update( if ($response->notFound() && data_get($response, 'status') === SymfonyResponse::HTTP_NOT_FOUND) { $this->throwNotFoundException( - json_encode($response->json()) + json_encode($response->json(), JSON_THROW_ON_ERROR) ); } @@ -156,13 +156,13 @@ public function update( && data_get($response, 'status') === SymfonyResponse::HTTP_CONFLICT ) { $this->throwConflictResponseException( - json_encode($response->json()) + json_encode($response->json(), JSON_THROW_ON_ERROR) ); } if ($response->clientError()) { $this->throwUpdateResponseException( - json_encode($response->json()), + json_encode($response->json(), JSON_THROW_ON_ERROR), $response->status() ); } @@ -181,13 +181,13 @@ public function delete(string $index, string|int $id): IndexResponseDto if ($response->notFound() && data_get($response, 'result') === 'not_found') { $this->throwNotFoundException( - json_encode($response->json()) + json_encode($response->json(), JSON_THROW_ON_ERROR) ); } if ($response->clientError()) { $this->throwDeleteResponseException( - json_encode($response->json()), + json_encode($response->json(), JSON_THROW_ON_ERROR), $response->status() ); } diff --git a/src/Contracts/AbstractClient.php b/src/Contracts/AbstractClient.php index 4aa953a..e1d74f8 100644 --- a/src/Contracts/AbstractClient.php +++ b/src/Contracts/AbstractClient.php @@ -17,7 +17,7 @@ abstract class AbstractClient { - protected function getBaseClient(): PendingRequest + public function getBaseClient(): PendingRequest { $apiKey = config('services.elasticsearch.api_key'); $port = config('services.elasticsearch.port'); @@ -39,7 +39,7 @@ protected function getBaseClient(): PendingRequest /** * @throws NotFoundResponseException */ - protected function throwNotFoundException(string $message, int $code = Response::HTTP_NOT_FOUND): void + public function throwNotFoundException(string $message, int $code = Response::HTTP_NOT_FOUND): void { throw new NotFoundResponseException( $message, @@ -50,7 +50,7 @@ protected function throwNotFoundException(string $message, int $code = Response: /** * @throws IndexNotFoundResponseException */ - protected function throwIndexNotFoundException(string $message, int $code = Response::HTTP_NOT_FOUND): void + public function throwIndexNotFoundException(string $message, int $code = Response::HTTP_NOT_FOUND): void { throw new IndexNotFoundResponseException( $message, @@ -61,7 +61,7 @@ protected function throwIndexNotFoundException(string $message, int $code = Resp /** * @throws SearchResponseException */ - protected function throwSearchResponseException(string $message, int $code = Response::HTTP_BAD_REQUEST): void + public function throwSearchResponseException(string $message, int $code = Response::HTTP_BAD_REQUEST): void { throw new SearchResponseException( $message, @@ -72,7 +72,7 @@ protected function throwSearchResponseException(string $message, int $code = Res /** * @throws IndexResponseException */ - protected function throwIndexResponseException(string $message, int $code = Response::HTTP_BAD_REQUEST): void + public function throwIndexResponseException(string $message, int $code = Response::HTTP_BAD_REQUEST): void { throw new IndexResponseException( $message, @@ -83,7 +83,7 @@ protected function throwIndexResponseException(string $message, int $code = Resp /** * @throws DeleteResponseException */ - protected function throwDeleteResponseException(string $message, int $code = Response::HTTP_BAD_REQUEST): void + public function throwDeleteResponseException(string $message, int $code = Response::HTTP_BAD_REQUEST): void { throw new DeleteResponseException( $message, @@ -94,7 +94,7 @@ protected function throwDeleteResponseException(string $message, int $code = Res /** * @throws UpdateResponseException */ - protected function throwUpdateResponseException(string $message, int $code = Response::HTTP_BAD_REQUEST): void + public function throwUpdateResponseException(string $message, int $code = Response::HTTP_BAD_REQUEST): void { throw new UpdateResponseException( $message, @@ -105,7 +105,7 @@ protected function throwUpdateResponseException(string $message, int $code = Res /** * @throws ConflictResponseException */ - protected function throwConflictResponseException(string $message, int $code = Response::HTTP_CONFLICT): void + public function throwConflictResponseException(string $message, int $code = Response::HTTP_CONFLICT): void { throw new ConflictResponseException( $message, diff --git a/src/Contracts/AliasInterface.php b/src/Contracts/AliasInterface.php new file mode 100644 index 0000000..12ccb6f --- /dev/null +++ b/src/Contracts/AliasInterface.php @@ -0,0 +1,21 @@ + + */ + public function getIndicesForAlias(string $alias): array; + + public function add(string $index, string $alias): bool; + + public function remove(string $index, string $alias): bool; + + public function runActions(array $actions): Response; + + public function replace(string $alias, string $newIndex, ?string $oldIndex = null): bool; +} \ No newline at end of file diff --git a/src/Contracts/ClientInterface.php b/src/Contracts/ClientInterface.php index f2e2750..7d77e5e 100644 --- a/src/Contracts/ClientInterface.php +++ b/src/Contracts/ClientInterface.php @@ -2,6 +2,7 @@ namespace Olekjs\Elasticsearch\Contracts; +use Illuminate\Http\Client\PendingRequest; use Olekjs\Elasticsearch\Dto\BulkResponseDto; use Olekjs\Elasticsearch\Dto\FindResponseDto; use Olekjs\Elasticsearch\Dto\IndexResponseDto; @@ -16,6 +17,7 @@ use Olekjs\Elasticsearch\Exceptions\NotFoundResponseException; use Olekjs\Elasticsearch\Exceptions\SearchResponseException; use Olekjs\Elasticsearch\Exceptions\UpdateResponseException; +use Symfony\Component\HttpFoundation\Response; interface ClientInterface { @@ -108,4 +110,41 @@ public function paginate(string $index, array $data = [], int $page = 1, int $pe * @throws CoreException */ public function bulk(BulkOperationInterface $bulk): BulkResponseDto; + + public function getBaseClient(): PendingRequest; + + /** + * @throws NotFoundResponseException + */ + public function throwNotFoundException(string $message, int $code = Response::HTTP_NOT_FOUND): void; + + /** + * @throws IndexNotFoundResponseException + */ + public function throwIndexNotFoundException(string $message, int $code = Response::HTTP_NOT_FOUND): void; + + /** + * @throws SearchResponseException + */ + public function throwSearchResponseException(string $message, int $code = Response::HTTP_BAD_REQUEST): void; + + /** + * @throws IndexResponseException + */ + public function throwIndexResponseException(string $message, int $code = Response::HTTP_BAD_REQUEST): void; + + /** + * @throws DeleteResponseException + */ + public function throwDeleteResponseException(string $message, int $code = Response::HTTP_BAD_REQUEST): void; + + /** + * @throws UpdateResponseException + */ + public function throwUpdateResponseException(string $message, int $code = Response::HTTP_BAD_REQUEST): void; + + /** + * @throws ConflictResponseException + */ + public function throwConflictResponseException(string $message, int $code = Response::HTTP_CONFLICT): void; } diff --git a/src/Contracts/IndexInterface.php b/src/Contracts/IndexInterface.php new file mode 100644 index 0000000..bf12f66 --- /dev/null +++ b/src/Contracts/IndexInterface.php @@ -0,0 +1,10 @@ +client->getBaseClient()->put($name, (object) $settings); + + if ($response->clientError()) { + $this->client->throwUpdateResponseException( + json_encode($response->json(), JSON_THROW_ON_ERROR), + $response->status() + ); + } + + return $response->successful(); + } + + public function delete(string $name): bool + { + $response = $this->client->getBaseClient()->delete($name); + + if ($response->clientError()) { + $this->client->throwDeleteResponseException( + json_encode($response->json(), JSON_THROW_ON_ERROR), + $response->status() + ); + } + + return $response->successful(); + } +} \ No newline at end of file diff --git a/tests/Integration/AliasTest.php b/tests/Integration/AliasTest.php new file mode 100644 index 0000000..96da715 --- /dev/null +++ b/tests/Integration/AliasTest.php @@ -0,0 +1,73 @@ +getIndicesForAlias('alias'); + + $this->assertSame(['test_1', 'test_2'], $indices); + } + + public function testAddMethod(): void + { + Http::fake(function () { + return Http::response( + file_get_contents('tests/Responses/alias_run_actions_success_response.json') + ); + }); + + $alias = new Alias(); + $added = $alias->add('index', 'alias'); + + $this->assertTrue($added); + } + + public function testRemoveMethod(): void + { + Http::fake(function () { + return Http::response( + file_get_contents('tests/Responses/alias_run_actions_success_response.json') + ); + }); + + $alias = new Alias(); + $added = $alias->remove('index', 'alias'); + + $this->assertTrue($added); + } + + public function testRunActionsMethod(): void + { + Http::fake(function () { + return Http::response( + file_get_contents('tests/Responses/alias_run_actions_success_response.json') + ); + }); + + $alias = new Alias(); + $response = $alias->runActions([ + [ + 'remove' => [ + 'index' => 'test', + 'alias' => 'test_alias', + ] + ] + ]); + + $this->assertTrue($response->successful()); + } +} \ No newline at end of file diff --git a/tests/Integration/ClientTest.php b/tests/Integration/ClientTest.php index 2d8256e..c22d11b 100644 --- a/tests/Integration/ClientTest.php +++ b/tests/Integration/ClientTest.php @@ -20,7 +20,7 @@ use Olekjs\Elasticsearch\Tests\TestCase; use Symfony\Component\HttpFoundation\Response; -final class ClientTest extends TestCase +class ClientTest extends TestCase { public function testSearchMethod(): void { diff --git a/tests/Integration/IndexTest.php b/tests/Integration/IndexTest.php new file mode 100644 index 0000000..f26d987 --- /dev/null +++ b/tests/Integration/IndexTest.php @@ -0,0 +1,38 @@ +create('index'); + + $this->assertTrue($added); + } + + public function testDeleteMethod(): void + { + Http::fake(function () { + return Http::response( + file_get_contents('tests/Responses/delete_index_response.json') + ); + }); + + $index = new Index(); + $deleted = $index->delete('index'); + + $this->assertTrue($deleted); + } +} \ No newline at end of file diff --git a/tests/Responses/alias_run_actions_success_response.json b/tests/Responses/alias_run_actions_success_response.json new file mode 100644 index 0000000..bc78e88 --- /dev/null +++ b/tests/Responses/alias_run_actions_success_response.json @@ -0,0 +1,3 @@ +{ + "acknowledged": true +} \ No newline at end of file diff --git a/tests/Responses/delete_index_response.json b/tests/Responses/delete_index_response.json new file mode 100644 index 0000000..bc78e88 --- /dev/null +++ b/tests/Responses/delete_index_response.json @@ -0,0 +1,3 @@ +{ + "acknowledged": true +} \ No newline at end of file diff --git a/tests/Responses/list_alias_indices_response.json b/tests/Responses/list_alias_indices_response.json new file mode 100644 index 0000000..7c4f55c --- /dev/null +++ b/tests/Responses/list_alias_indices_response.json @@ -0,0 +1,12 @@ +{ + "test_1": { + "aliases": { + "alias_test": {} + } + }, + "test_2": { + "aliases": { + "alias_test": {} + } + } +} \ No newline at end of file diff --git a/tests/Responses/store_index_response.json b/tests/Responses/store_index_response.json new file mode 100644 index 0000000..bc205da --- /dev/null +++ b/tests/Responses/store_index_response.json @@ -0,0 +1,5 @@ +{ + "acknowledged": true, + "shards_acknowledged": true, + "index": "test" +} \ No newline at end of file