From acade92de444944a5a481976876b61431a6ef9fe Mon Sep 17 00:00:00 2001 From: Enrico Zimuel Date: Tue, 26 Mar 2024 09:12:06 +0100 Subject: [PATCH 1/7] Added mapTo feature, see #1398 (#1399) * Added mapTo feature, see #1398 * Fixed php-http/message-factory issue and extended memory to 256M for phpstan --- composer.json | 7 ++- src/Response/Elasticsearch.php | 62 ++++++++++++++++++++ src/Utility.php | 14 +++++ tests/Response/ElasticsearchTest.php | 84 +++++++++++++++++++++++++++- tests/Response/TestMapClass.php | 24 ++++++++ 5 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 tests/Response/TestMapClass.php diff --git a/composer.json b/composer.json index 2e7d30b68..50c5c1838 100644 --- a/composer.json +++ b/composer.json @@ -26,8 +26,9 @@ "symfony/finder": "~4.0", "nyholm/psr7": "^1.5", "php-http/mock-client": "^1.5", - "symfony/http-client": "^5.0|^6.0", - "psr/http-factory" : "^1.0" + "symfony/http-client": "^5.0|^6.0|^7.0", + "psr/http-factory" : "^1.0", + "php-http/message-factory" : "^1.0" }, "autoload": { "psr-4": { @@ -51,7 +52,7 @@ "vendor/bin/phpunit --testdox -c phpunit-integration-cloud-tests.xml" ], "phpstan": [ - "phpstan analyse src --level 2 --no-progress" + "phpstan analyse src --level 2 --no-progress --memory-limit 256M" ] }, "config": { diff --git a/src/Response/Elasticsearch.php b/src/Response/Elasticsearch.php index 164d999fa..267f72b12 100644 --- a/src/Response/Elasticsearch.php +++ b/src/Response/Elasticsearch.php @@ -15,17 +15,20 @@ namespace Elastic\Elasticsearch\Response; use ArrayAccess; +use DateTime; use Elastic\Elasticsearch\Exception\ArrayAccessException; use Elastic\Elasticsearch\Exception\ClientResponseException; use Elastic\Elasticsearch\Exception\ServerResponseException; use Elastic\Elasticsearch\Traits\MessageResponseTrait; use Elastic\Elasticsearch\Traits\ProductCheckTrait; +use Elastic\Elasticsearch\Utility; use Elastic\Transport\Exception\UnknownContentTypeException; use Elastic\Transport\Serializer\CsvSerializer; use Elastic\Transport\Serializer\JsonSerializer; use Elastic\Transport\Serializer\NDJsonSerializer; use Elastic\Transport\Serializer\XmlSerializer; use Psr\Http\Message\ResponseInterface; +use stdClass; /** * Wraps a PSR-7 ResponseInterface offering helpers to deserialize the body response @@ -224,4 +227,63 @@ public function offsetUnset($offset): void { throw new ArrayAccessException('The array is reading only'); } + + /** + * Map the response body to an object of a specific class + * by default the class is the PHP standard one (stdClass) + * + * This mapping works only for ES|QL results (with columns and values) + * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/esql.html + * + * @return object[] + */ + public function mapTo(string $class = stdClass::class): array + { + $response = $this->asArray(); + if (!isset($response['columns']) || !isset($response['values'])) { + throw new UnknownContentTypeException(sprintf( + "The response is not a valid ES|QL result. I cannot mapTo(\"%s\")", + $class + )); + } + $iterator = []; + $ncol = count($response['columns']); + foreach ($response['values'] as $value) { + $obj = new $class; + for ($i=0; $i < $ncol; $i++) { + $field = Utility::formatVariableName($response['columns'][$i]['name']); + if ($class !== stdClass::class && !property_exists($obj, $field)) { + continue; + } + switch($response['columns'][$i]['type']) { + case 'boolean': + $obj->{$field} = (bool) $value[$i]; + break; + case 'date': + $obj->{$field} = new DateTime($value[$i]); + break; + case 'alias': + case 'text': + case 'keyword': + case 'ip': + $obj->{$field} = (string) $value[$i]; + break; + case 'integer': + $obj->{$field} = (int) $value[$i]; + break; + case 'long': + case 'double': + $obj->{$field} = (float) $value[$i]; + break; + case 'null': + $obj->{$field} = null; + break; + default: + $obj->{$field} = $value[$i]; + } + } + $iterator[] = $obj; + } + return $iterator; + } } \ No newline at end of file diff --git a/src/Utility.php b/src/Utility.php index 0bc8593e1..d54185ce5 100644 --- a/src/Utility.php +++ b/src/Utility.php @@ -45,4 +45,18 @@ public static function urlencode(string $url): string ? urlencode($url) : rawurlencode($url); } + + /** + * Remove all the characters not valid for a PHP variable name + * The valid characters are: a-z, A-Z, 0-9 and _ (underscore) + * The variable name CANNOT start with a number + */ + public static function formatVariableName(string $var): string + { + // If the first character is a digit, we append the underscore + if (is_int($var[0])) { + $var = '_' . $var; + } + return preg_replace('/[^a-zA-Z0-9_]/', '', $var); + } } \ No newline at end of file diff --git a/tests/Response/ElasticsearchTest.php b/tests/Response/ElasticsearchTest.php index 8e5f0fbee..1a3e30827 100644 --- a/tests/Response/ElasticsearchTest.php +++ b/tests/Response/ElasticsearchTest.php @@ -14,15 +14,17 @@ namespace Elastic\Elasticsearch\Tests\Response; +use DateTime; use Elastic\Elasticsearch\Exception\ArrayAccessException; use Elastic\Elasticsearch\Exception\ClientResponseException; use Elastic\Elasticsearch\Exception\ProductCheckException; use Elastic\Elasticsearch\Exception\ServerResponseException; use Elastic\Elasticsearch\Response\Elasticsearch; +use Elastic\Transport\Exception\UnknownContentTypeException; use Nyholm\Psr7\Factory\Psr17Factory; use PHPUnit\Framework\TestCase; use Psr\Http\Message\ResponseInterface; - +use stdClass; class ElasticsearchTest extends TestCase { protected Psr17Factory $psr17Factory; @@ -215,4 +217,84 @@ public function testWithStatusForPsr7Version1And2Compatibility() $this->elasticsearch = $this->elasticsearch->withStatus(400); $this->assertEquals(400, $this->elasticsearch->getStatusCode()); } + + public function testMapToStdClassAsDefault() + { + $array = [ + 'columns' => [ + ['name' => 'a', 'type' => 'integer'], + ['name' => 'b', 'type' => 'date'] + ], + 'values' => [ + [1, '2023-10-23T12:15:03.360Z'], + [3, '2023-10-23T13:55:01.543Z'] + ] + ]; + $body = $this->psr17Factory->createStream(json_encode($array)); + $this->elasticsearch->setResponse($this->response200->withBody($body)); + + $iterator = $this->elasticsearch->mapTo(); + $this->assertIsArray($iterator); + $this->assertEquals(stdClass::class, get_class($iterator[0])); + $this->assertEquals(stdClass::class, get_class($iterator[1])); + $this->assertEquals('integer', gettype($iterator[0]->a)); + $this->assertEquals(DateTime::class, get_class($iterator[0]->b)); + $this->assertEquals('integer', gettype($iterator[1]->a)); + $this->assertEquals(DateTime::class, get_class($iterator[1]->b)); + } + + public function testMapToStdClass() + { + $array = [ + 'columns' => [ + ['name' => 'a', 'type' => 'integer'], + ['name' => 'b', 'type' => 'date'] + ], + 'values' => [ + [1, '2023-10-23T12:15:03.360Z'], + [3, '2023-10-23T13:55:01.543Z'] + ] + ]; + $body = $this->psr17Factory->createStream(json_encode($array)); + $this->elasticsearch->setResponse($this->response200->withBody($body)); + + $iterator = $this->elasticsearch->mapTo(stdClass::class); + $this->assertIsArray($iterator); + $this->assertEquals(stdClass::class, get_class($iterator[0])); + $this->assertEquals(stdClass::class, get_class($iterator[1])); + } + + public function testMapToWithoutEsqlResponseWillThrowException() + { + $array = ['foo' => 'bar']; + $body = $this->psr17Factory->createStream(json_encode($array)); + $this->elasticsearch->setResponse($this->response200->withBody($body)); + + $this->expectException(UnknownContentTypeException::class); + $iterator = $this->elasticsearch->mapTo(); + } + + public function testMapToCustomClass() + { + $array = [ + 'columns' => [ + ['name' => 'a', 'type' => 'integer'], + ['name' => 'b', 'type' => 'date'] + ], + 'values' => [ + [1, '2023-10-23T12:15:03.360Z'], + [3, '2023-10-23T13:55:01.543Z'] + ] + ]; + $body = $this->psr17Factory->createStream(json_encode($array)); + $this->elasticsearch->setResponse($this->response200->withBody($body)); + + $iterator = $this->elasticsearch->mapTo(TestMapClass::class); + + $this->assertIsArray($iterator); + $this->assertEquals(TestMapClass::class, get_class($iterator[0])); + $this->assertEquals('integer', gettype($iterator[0]->a)); + $this->assertEquals(DateTime::class, get_class($iterator[0]->b)); + $this->assertEquals('', $iterator[0]->c); + } } \ No newline at end of file diff --git a/tests/Response/TestMapClass.php b/tests/Response/TestMapClass.php new file mode 100644 index 000000000..e319ac71c --- /dev/null +++ b/tests/Response/TestMapClass.php @@ -0,0 +1,24 @@ + Date: Tue, 26 Mar 2024 09:17:22 +0100 Subject: [PATCH 2/7] Added PHP 8.3 and updated ES-VERSION --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4c96f214d..8c9828bbf 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,9 +9,9 @@ jobs: strategy: matrix: - php-version: [7.4, 8.0, 8.1, 8.2] + php-version: [7.4, 8.0, 8.1, 8.2, 8.3] os: [ubuntu-latest] - es-version: [8.9-SNAPSHOT] + es-version: [8.13-SNAPSHOT] steps: - name: Checkout From e68f81dcb0808f0704fbd0688c401d3b852eaa4a Mon Sep 17 00:00:00 2001 From: Enrico Zimuel Date: Tue, 26 Mar 2024 10:22:08 +0100 Subject: [PATCH 3/7] Updated github checkout and cache to v4 --- .github/workflows/license.yml | 2 +- .github/workflows/test.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/license.yml b/.github/workflows/license.yml index 8583ee456..89bccb01d 100644 --- a/.github/workflows/license.yml +++ b/.github/workflows/license.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Check license headers run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8c9828bbf..c939b81c9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Use PHP ${{ matrix.php-version }} uses: shivammathur/setup-php@v2 @@ -30,7 +30,7 @@ jobs: id: composercache run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - name: Cache dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ steps.composercache.outputs.dir }} key: ${{ runner.os }}-php-${{ matrix.php-version }}-${{ hashFiles('**/composer.json') }} From c8f32a27f84f91510bfb84b0a425e65fb5bd9736 Mon Sep 17 00:00:00 2001 From: Enrico Zimuel Date: Tue, 26 Mar 2024 11:25:57 +0100 Subject: [PATCH 4/7] Updated APIs to ES 8.13 --- .buildkite/pipeline.yml | 2 +- src/Endpoints/AsyncSearch.php | 3 +- src/Endpoints/Connector.php | 198 +++++++++++++++++++++++++++- src/Endpoints/ConnectorSyncJob.php | 3 +- src/Endpoints/Esql.php | 82 +++++++++++- src/Endpoints/Indices.php | 42 +++++- src/Endpoints/Inference.php | 64 +++++---- src/Endpoints/Profiling.php | 68 ++++++++++ src/Endpoints/Security.php | 35 +++++ src/Endpoints/Synonyms.php | 7 - src/Endpoints/TextStructure.php | 36 +++++ src/Traits/ClientEndpointsTrait.php | 9 +- 12 files changed, 507 insertions(+), 42 deletions(-) diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 3e23889ed..ff804dfd7 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -5,7 +5,7 @@ steps: env: PHP_VERSION: "{{ matrix.php }}" TEST_SUITE: "{{ matrix.suite }}" - STACK_VERSION: 8.12-SNAPSHOT + STACK_VERSION: 8.13.0-SNAPSHOT matrix: setup: suite: diff --git a/src/Endpoints/AsyncSearch.php b/src/Endpoints/AsyncSearch.php index b11a52059..46cb8bf22 100644 --- a/src/Endpoints/AsyncSearch.php +++ b/src/Endpoints/AsyncSearch.php @@ -108,6 +108,7 @@ public function get(array $params = []) * * @param array{ * id: string, // (REQUIRED) The async search ID + * keep_alive: time, // Specify the time interval in which the results (partial or final) for this search will be available * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) * human: boolean, // Return human readable values for statistics. (DEFAULT: true) * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) @@ -128,7 +129,7 @@ public function status(array $params = []) $url = '/_async_search/status/' . $this->encode($params['id']); $method = 'GET'; - $url = $this->addQueryString($url, $params, ['pretty','human','error_trace','source','filter_path']); + $url = $this->addQueryString($url, $params, ['keep_alive','pretty','human','error_trace','source','filter_path']); $headers = [ 'Accept' => 'application/json', ]; diff --git a/src/Endpoints/Connector.php b/src/Endpoints/Connector.php index fbd8fcd44..e7cc61b7e 100644 --- a/src/Endpoints/Connector.php +++ b/src/Endpoints/Connector.php @@ -182,7 +182,11 @@ public function lastSync(array $params = []) * * @param array{ * from: int, // Starting offset (default: 0) - * size: int, // specifies a max number of results to get (default: 100) + * size: int, // Specifies a max number of results to get (default: 100) + * index_name: list, // A comma-separated list of connector index names to fetch connector documents for + * connector_name: list, // A comma-separated list of connector names to fetch connector documents for + * service_type: list, // A comma-separated list of connector service types to fetch connector documents for + * query: string, // A search string for querying connectors, filtering results by matching against connector names, descriptions, and index names * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) * human: boolean, // Return human readable values for statistics. (DEFAULT: true) * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) @@ -201,7 +205,7 @@ public function list(array $params = []) $url = '/_connector'; $method = 'GET'; - $url = $this->addQueryString($url, $params, ['from','size','pretty','human','error_trace','source','filter_path']); + $url = $this->addQueryString($url, $params, ['from','size','index_name','connector_name','service_type','query','pretty','human','error_trace','source','filter_path']); $headers = [ 'Accept' => 'application/json', ]; @@ -283,6 +287,44 @@ public function put(array $params = []) } + /** + * Updates the API key id and/or API key secret id fields in the connector document. + * + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/update-connector-api-key-id-api.html + * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release + * + * @param array{ + * connector_id: string, // (REQUIRED) The unique identifier of the connector to be updated. + * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) + * human: boolean, // Return human readable values for statistics. (DEFAULT: true) + * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) + * source: string, // The URL-encoded request definition. Useful for libraries that do not accept a request body for non-POST requests. + * filter_path: list, // A comma-separated list of filters used to reduce the response. + * body: array, // (REQUIRED) An object containing the connector's API key id and/or Connector Secret document id for that API key. + * } $params + * + * @throws MissingParameterException if a required parameter is missing + * @throws NoNodeAvailableException if all the hosts are offline + * @throws ClientResponseException if the status code of response is 4xx + * @throws ServerResponseException if the status code of response is 5xx + * + * @return Elasticsearch|Promise + */ + public function updateApiKeyId(array $params = []) + { + $this->checkRequiredParameters(['connector_id','body'], $params); + $url = '/_connector/' . $this->encode($params['connector_id']) . '/_api_key_id'; + $method = 'PUT'; + + $url = $this->addQueryString($url, $params, ['pretty','human','error_trace','source','filter_path']); + $headers = [ + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + ]; + return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); + } + + /** * Updates the connector configuration. * @@ -397,6 +439,44 @@ public function updateFiltering(array $params = []) } + /** + * Updates the index name of the connector. + * + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/update-connector-index-name-api.html + * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release + * + * @param array{ + * connector_id: string, // (REQUIRED) The unique identifier of the connector to be updated. + * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) + * human: boolean, // Return human readable values for statistics. (DEFAULT: true) + * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) + * source: string, // The URL-encoded request definition. Useful for libraries that do not accept a request body for non-POST requests. + * filter_path: list, // A comma-separated list of filters used to reduce the response. + * body: array, // (REQUIRED) An object containing the connector's index name. + * } $params + * + * @throws MissingParameterException if a required parameter is missing + * @throws NoNodeAvailableException if all the hosts are offline + * @throws ClientResponseException if the status code of response is 4xx + * @throws ServerResponseException if the status code of response is 5xx + * + * @return Elasticsearch|Promise + */ + public function updateIndexName(array $params = []) + { + $this->checkRequiredParameters(['connector_id','body'], $params); + $url = '/_connector/' . $this->encode($params['connector_id']) . '/_index_name'; + $method = 'PUT'; + + $url = $this->addQueryString($url, $params, ['pretty','human','error_trace','source','filter_path']); + $headers = [ + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + ]; + return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); + } + + /** * Updates the name and/or description fields in the connector document. * @@ -435,6 +515,44 @@ public function updateName(array $params = []) } + /** + * Updates the is_native flag of the connector. + * + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/connector-apis.html + * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release + * + * @param array{ + * connector_id: string, // (REQUIRED) The unique identifier of the connector to be updated. + * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) + * human: boolean, // Return human readable values for statistics. (DEFAULT: true) + * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) + * source: string, // The URL-encoded request definition. Useful for libraries that do not accept a request body for non-POST requests. + * filter_path: list, // A comma-separated list of filters used to reduce the response. + * body: array, // (REQUIRED) An object containing the connector's is_native flag + * } $params + * + * @throws MissingParameterException if a required parameter is missing + * @throws NoNodeAvailableException if all the hosts are offline + * @throws ClientResponseException if the status code of response is 4xx + * @throws ServerResponseException if the status code of response is 5xx + * + * @return Elasticsearch|Promise + */ + public function updateNative(array $params = []) + { + $this->checkRequiredParameters(['connector_id','body'], $params); + $url = '/_connector/' . $this->encode($params['connector_id']) . '/_native'; + $method = 'PUT'; + + $url = $this->addQueryString($url, $params, ['pretty','human','error_trace','source','filter_path']); + $headers = [ + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + ]; + return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); + } + + /** * Updates the pipeline field in the connector document. * @@ -509,4 +627,80 @@ public function updateScheduling(array $params = []) ]; return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); } + + + /** + * Updates the service type of the connector. + * + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/update-connector-service-type-api.html + * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release + * + * @param array{ + * connector_id: string, // (REQUIRED) The unique identifier of the connector to be updated. + * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) + * human: boolean, // Return human readable values for statistics. (DEFAULT: true) + * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) + * source: string, // The URL-encoded request definition. Useful for libraries that do not accept a request body for non-POST requests. + * filter_path: list, // A comma-separated list of filters used to reduce the response. + * body: array, // (REQUIRED) An object containing the connector's service type. + * } $params + * + * @throws MissingParameterException if a required parameter is missing + * @throws NoNodeAvailableException if all the hosts are offline + * @throws ClientResponseException if the status code of response is 4xx + * @throws ServerResponseException if the status code of response is 5xx + * + * @return Elasticsearch|Promise + */ + public function updateServiceType(array $params = []) + { + $this->checkRequiredParameters(['connector_id','body'], $params); + $url = '/_connector/' . $this->encode($params['connector_id']) . '/_service_type'; + $method = 'PUT'; + + $url = $this->addQueryString($url, $params, ['pretty','human','error_trace','source','filter_path']); + $headers = [ + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + ]; + return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); + } + + + /** + * Updates the status of the connector. + * + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/update-connector-status-api.html + * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release + * + * @param array{ + * connector_id: string, // (REQUIRED) The unique identifier of the connector to be updated. + * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) + * human: boolean, // Return human readable values for statistics. (DEFAULT: true) + * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) + * source: string, // The URL-encoded request definition. Useful for libraries that do not accept a request body for non-POST requests. + * filter_path: list, // A comma-separated list of filters used to reduce the response. + * body: array, // (REQUIRED) An object containing the connector's status. + * } $params + * + * @throws MissingParameterException if a required parameter is missing + * @throws NoNodeAvailableException if all the hosts are offline + * @throws ClientResponseException if the status code of response is 4xx + * @throws ServerResponseException if the status code of response is 5xx + * + * @return Elasticsearch|Promise + */ + public function updateStatus(array $params = []) + { + $this->checkRequiredParameters(['connector_id','body'], $params); + $url = '/_connector/' . $this->encode($params['connector_id']) . '/_status'; + $method = 'PUT'; + + $url = $this->addQueryString($url, $params, ['pretty','human','error_trace','source','filter_path']); + $headers = [ + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + ]; + return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); + } } diff --git a/src/Endpoints/ConnectorSyncJob.php b/src/Endpoints/ConnectorSyncJob.php index 7d05fd64c..b46cf9ecf 100644 --- a/src/Endpoints/ConnectorSyncJob.php +++ b/src/Endpoints/ConnectorSyncJob.php @@ -221,6 +221,7 @@ public function get(array $params = []) * size: int, // specifies a max number of results to get (default: 100) * status: string, // Sync job status, which sync jobs are fetched for * connector_id: string, // Id of the connector to fetch the sync jobs for + * job_type: list, // A comma-separated list of job types * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) * human: boolean, // Return human readable values for statistics. (DEFAULT: true) * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) @@ -239,7 +240,7 @@ public function list(array $params = []) $url = '/_connector/_sync_job'; $method = 'GET'; - $url = $this->addQueryString($url, $params, ['from','size','status','connector_id','pretty','human','error_trace','source','filter_path']); + $url = $this->addQueryString($url, $params, ['from','size','status','connector_id','job_type','pretty','human','error_trace','source','filter_path']); $headers = [ 'Accept' => 'application/json', ]; diff --git a/src/Endpoints/Esql.php b/src/Endpoints/Esql.php index c19392459..19ddac353 100644 --- a/src/Endpoints/Esql.php +++ b/src/Endpoints/Esql.php @@ -28,6 +28,83 @@ */ class Esql extends AbstractEndpoint { + /** + * Executes an ESQL request asynchronously + * + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/esql-async-query-api.html + * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release + * + * @param array{ + * format: string, // a short version of the Accept header, e.g. json, yaml + * delimiter: string, // The character to use between values within a CSV row. Only valid for the csv format. + * drop_null_columns: boolean, // Should entirely null columns be removed from the results? Their name and type will be returning in a new `all_columns` section. + * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) + * human: boolean, // Return human readable values for statistics. (DEFAULT: true) + * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) + * source: string, // The URL-encoded request definition. Useful for libraries that do not accept a request body for non-POST requests. + * filter_path: list, // A comma-separated list of filters used to reduce the response. + * body: array, // (REQUIRED) Use the `query` element to start a query. Use `columnar` to format the answer. + * } $params + * + * @throws NoNodeAvailableException if all the hosts are offline + * @throws ClientResponseException if the status code of response is 4xx + * @throws ServerResponseException if the status code of response is 5xx + * + * @return Elasticsearch|Promise + */ + public function asyncQuery(array $params = []) + { + $this->checkRequiredParameters(['body'], $params); + $url = '/_query/async'; + $method = 'POST'; + + $url = $this->addQueryString($url, $params, ['format','delimiter','drop_null_columns','pretty','human','error_trace','source','filter_path']); + $headers = [ + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + ]; + return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); + } + + + /** + * Retrieves the results of a previously submitted async query request given its ID. + * + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/esql-async-query-get-api.html + * + * @param array{ + * id: string, // (REQUIRED) The async query ID + * wait_for_completion_timeout: time, // Specify the time that the request should block waiting for the final response + * keep_alive: time, // Specify the time interval in which the results (partial or final) for this search will be available + * drop_null_columns: boolean, // Should entirely null columns be removed from the results? Their name and type will be returning in a new `all_columns` section. + * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) + * human: boolean, // Return human readable values for statistics. (DEFAULT: true) + * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) + * source: string, // The URL-encoded request definition. Useful for libraries that do not accept a request body for non-POST requests. + * filter_path: list, // A comma-separated list of filters used to reduce the response. + * } $params + * + * @throws MissingParameterException if a required parameter is missing + * @throws NoNodeAvailableException if all the hosts are offline + * @throws ClientResponseException if the status code of response is 4xx + * @throws ServerResponseException if the status code of response is 5xx + * + * @return Elasticsearch|Promise + */ + public function asyncQueryGet(array $params = []) + { + $this->checkRequiredParameters(['id'], $params); + $url = '/_query/async/' . $this->encode($params['id']); + $method = 'GET'; + + $url = $this->addQueryString($url, $params, ['wait_for_completion_timeout','keep_alive','drop_null_columns','pretty','human','error_trace','source','filter_path']); + $headers = [ + 'Accept' => 'application/json', + ]; + return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); + } + + /** * Executes an ESQL request * @@ -37,12 +114,13 @@ class Esql extends AbstractEndpoint * @param array{ * format: string, // a short version of the Accept header, e.g. json, yaml * delimiter: string, // The character to use between values within a CSV row. Only valid for the csv format. + * drop_null_columns: boolean, // Should entirely null columns be removed from the results? Their name and type will be returning in a new `all_columns` section. * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) * human: boolean, // Return human readable values for statistics. (DEFAULT: true) * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) * source: string, // The URL-encoded request definition. Useful for libraries that do not accept a request body for non-POST requests. * filter_path: list, // A comma-separated list of filters used to reduce the response. - * body: array, // (REQUIRED) Use the `query` element to start a query. Use `time_zone` to specify an execution time zone and `columnar` to format the answer. + * body: array, // (REQUIRED) Use the `query` element to start a query. Use `columnar` to format the answer. * } $params * * @throws NoNodeAvailableException if all the hosts are offline @@ -57,7 +135,7 @@ public function query(array $params = []) $url = '/_query'; $method = 'POST'; - $url = $this->addQueryString($url, $params, ['format','delimiter','pretty','human','error_trace','source','filter_path']); + $url = $this->addQueryString($url, $params, ['format','delimiter','drop_null_columns','pretty','human','error_trace','source','filter_path']); $headers = [ 'Accept' => 'application/json', 'Content-Type' => 'application/json', diff --git a/src/Endpoints/Indices.php b/src/Endpoints/Indices.php index 4614144d7..4ad664e93 100644 --- a/src/Endpoints/Indices.php +++ b/src/Endpoints/Indices.php @@ -1880,6 +1880,45 @@ public function reloadSearchAnalyzers(array $params = []) } + /** + * Resolves the specified index expressions to return information about each cluster, including the local cluster, if included. + * + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-resolve-cluster-api.html + * + * @param array{ + * name: list, // (REQUIRED) A comma-separated list of cluster:index names or wildcard expressions + * ignore_unavailable: boolean, // Whether specified concrete indices should be ignored when unavailable (missing or closed) + * ignore_throttled: boolean, // Whether specified concrete, expanded or aliased indices should be ignored when throttled + * allow_no_indices: boolean, // Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * expand_wildcards: enum, // Whether wildcard expressions should get expanded to open or closed indices (default: open) + * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) + * human: boolean, // Return human readable values for statistics. (DEFAULT: true) + * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) + * source: string, // The URL-encoded request definition. Useful for libraries that do not accept a request body for non-POST requests. + * filter_path: list, // A comma-separated list of filters used to reduce the response. + * } $params + * + * @throws MissingParameterException if a required parameter is missing + * @throws NoNodeAvailableException if all the hosts are offline + * @throws ClientResponseException if the status code of response is 4xx + * @throws ServerResponseException if the status code of response is 5xx + * + * @return Elasticsearch|Promise + */ + public function resolveCluster(array $params = []) + { + $this->checkRequiredParameters(['name'], $params); + $url = '/_resolve/cluster/' . $this->encode($params['name']); + $method = 'GET'; + + $url = $this->addQueryString($url, $params, ['ignore_unavailable','ignore_throttled','allow_no_indices','expand_wildcards','pretty','human','error_trace','source','filter_path']); + $headers = [ + 'Accept' => 'application/json', + ]; + return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); + } + + /** * Returns information about any matching indices, aliases, and data streams * @@ -1929,6 +1968,7 @@ public function resolveIndex(array $params = []) * dry_run: boolean, // If set to true the rollover action will only be validated but not actually performed even if a condition matches. The default is false * master_timeout: time, // Specify timeout for connection to master * wait_for_active_shards: string, // Set the number of active shards to wait for on the newly created rollover index before the operation returns. + * lazy: boolean, // If set to true, the rollover action will only mark a data stream to signal that it needs to be rolled over at the next write. Only allowed on data streams. * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) * human: boolean, // Return human readable values for statistics. (DEFAULT: true) * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) @@ -1954,7 +1994,7 @@ public function rollover(array $params = []) $url = '/' . $this->encode($params['alias']) . '/_rollover'; $method = 'POST'; } - $url = $this->addQueryString($url, $params, ['timeout','dry_run','master_timeout','wait_for_active_shards','pretty','human','error_trace','source','filter_path']); + $url = $this->addQueryString($url, $params, ['timeout','dry_run','master_timeout','wait_for_active_shards','lazy','pretty','human','error_trace','source','filter_path']); $headers = [ 'Accept' => 'application/json', 'Content-Type' => 'application/json', diff --git a/src/Endpoints/Inference.php b/src/Endpoints/Inference.php index 835d59c49..2feba9f54 100644 --- a/src/Endpoints/Inference.php +++ b/src/Endpoints/Inference.php @@ -35,8 +35,8 @@ class Inference extends AbstractEndpoint * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release * * @param array{ - * task_type: string, // (REQUIRED) The model task type - * model_id: string, // (REQUIRED) The model Id + * inference_id: string, // (REQUIRED) The model Id + * task_type: string, // The task type * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) * human: boolean, // Return human readable values for statistics. (DEFAULT: true) * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) @@ -53,10 +53,14 @@ class Inference extends AbstractEndpoint */ public function deleteModel(array $params = []) { - $this->checkRequiredParameters(['task_type','model_id'], $params); - $url = '/_inference/' . $this->encode($params['task_type']) . '/' . $this->encode($params['model_id']); - $method = 'DELETE'; - + $this->checkRequiredParameters(['inference_id'], $params); + if (isset($params['task_type'])) { + $url = '/_inference/' . $this->encode($params['task_type']) . '/' . $this->encode($params['inference_id']); + $method = 'DELETE'; + } else { + $url = '/_inference/' . $this->encode($params['inference_id']); + $method = 'DELETE'; + } $url = $this->addQueryString($url, $params, ['pretty','human','error_trace','source','filter_path']); $headers = [ 'Accept' => 'application/json', @@ -72,8 +76,8 @@ public function deleteModel(array $params = []) * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release * * @param array{ - * task_type: string, // (REQUIRED) The model task type - * model_id: string, // (REQUIRED) The model Id + * inference_id: string, // (REQUIRED) The inference Id + * task_type: string, // The task type * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) * human: boolean, // Return human readable values for statistics. (DEFAULT: true) * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) @@ -90,10 +94,14 @@ public function deleteModel(array $params = []) */ public function getModel(array $params = []) { - $this->checkRequiredParameters(['task_type','model_id'], $params); - $url = '/_inference/' . $this->encode($params['task_type']) . '/' . $this->encode($params['model_id']); - $method = 'GET'; - + $this->checkRequiredParameters(['inference_id'], $params); + if (isset($params['task_type'])) { + $url = '/_inference/' . $this->encode($params['task_type']) . '/' . $this->encode($params['inference_id']); + $method = 'GET'; + } else { + $url = '/_inference/' . $this->encode($params['inference_id']); + $method = 'GET'; + } $url = $this->addQueryString($url, $params, ['pretty','human','error_trace','source','filter_path']); $headers = [ 'Accept' => 'application/json', @@ -109,8 +117,8 @@ public function getModel(array $params = []) * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release * * @param array{ - * task_type: string, // (REQUIRED) The model task type - * model_id: string, // (REQUIRED) The model Id + * inference_id: string, // (REQUIRED) The inference Id + * task_type: string, // The task type * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) * human: boolean, // Return human readable values for statistics. (DEFAULT: true) * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) @@ -128,10 +136,14 @@ public function getModel(array $params = []) */ public function inference(array $params = []) { - $this->checkRequiredParameters(['task_type','model_id'], $params); - $url = '/_inference/' . $this->encode($params['task_type']) . '/' . $this->encode($params['model_id']); - $method = 'POST'; - + $this->checkRequiredParameters(['inference_id'], $params); + if (isset($params['task_type'])) { + $url = '/_inference/' . $this->encode($params['task_type']) . '/' . $this->encode($params['inference_id']); + $method = 'POST'; + } else { + $url = '/_inference/' . $this->encode($params['inference_id']); + $method = 'POST'; + } $url = $this->addQueryString($url, $params, ['pretty','human','error_trace','source','filter_path']); $headers = [ 'Accept' => 'application/json', @@ -148,8 +160,8 @@ public function inference(array $params = []) * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release * * @param array{ - * task_type: string, // (REQUIRED) The model task type - * model_id: string, // (REQUIRED) The model Id + * inference_id: string, // (REQUIRED) The inference Id + * task_type: string, // The task type * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) * human: boolean, // Return human readable values for statistics. (DEFAULT: true) * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) @@ -167,10 +179,14 @@ public function inference(array $params = []) */ public function putModel(array $params = []) { - $this->checkRequiredParameters(['task_type','model_id'], $params); - $url = '/_inference/' . $this->encode($params['task_type']) . '/' . $this->encode($params['model_id']); - $method = 'PUT'; - + $this->checkRequiredParameters(['inference_id'], $params); + if (isset($params['task_type'])) { + $url = '/_inference/' . $this->encode($params['task_type']) . '/' . $this->encode($params['inference_id']); + $method = 'PUT'; + } else { + $url = '/_inference/' . $this->encode($params['inference_id']); + $method = 'PUT'; + } $url = $this->addQueryString($url, $params, ['pretty','human','error_trace','source','filter_path']); $headers = [ 'Accept' => 'application/json', diff --git a/src/Endpoints/Profiling.php b/src/Endpoints/Profiling.php index ed7c3d2e7..fb15418f6 100644 --- a/src/Endpoints/Profiling.php +++ b/src/Endpoints/Profiling.php @@ -28,6 +28,74 @@ */ class Profiling extends AbstractEndpoint { + /** + * Extracts a UI-optimized structure to render flamegraphs from Universal Profiling. + * + * @see https://www.elastic.co/guide/en/observability/current/universal-profiling.html + * + * @param array{ + * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) + * human: boolean, // Return human readable values for statistics. (DEFAULT: true) + * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) + * source: string, // The URL-encoded request definition. Useful for libraries that do not accept a request body for non-POST requests. + * filter_path: list, // A comma-separated list of filters used to reduce the response. + * body: array, // (REQUIRED) The filter conditions for the flamegraph + * } $params + * + * @throws NoNodeAvailableException if all the hosts are offline + * @throws ClientResponseException if the status code of response is 4xx + * @throws ServerResponseException if the status code of response is 5xx + * + * @return Elasticsearch|Promise + */ + public function flamegraph(array $params = []) + { + $this->checkRequiredParameters(['body'], $params); + $url = '/_profiling/flamegraph'; + $method = 'POST'; + + $url = $this->addQueryString($url, $params, ['pretty','human','error_trace','source','filter_path']); + $headers = [ + 'Accept' => 'application/json', + ]; + return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); + } + + + /** + * Extracts raw stacktrace information from Universal Profiling. + * + * @see https://www.elastic.co/guide/en/observability/current/universal-profiling.html + * + * @param array{ + * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) + * human: boolean, // Return human readable values for statistics. (DEFAULT: true) + * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) + * source: string, // The URL-encoded request definition. Useful for libraries that do not accept a request body for non-POST requests. + * filter_path: list, // A comma-separated list of filters used to reduce the response. + * body: array, // (REQUIRED) The filter conditions for stacktraces + * } $params + * + * @throws NoNodeAvailableException if all the hosts are offline + * @throws ClientResponseException if the status code of response is 4xx + * @throws ServerResponseException if the status code of response is 5xx + * + * @return Elasticsearch|Promise + */ + public function stacktraces(array $params = []) + { + $this->checkRequiredParameters(['body'], $params); + $url = '/_profiling/stacktraces'; + $method = 'POST'; + + $url = $this->addQueryString($url, $params, ['pretty','human','error_trace','source','filter_path']); + $headers = [ + 'Accept' => 'application/json', + ]; + return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); + } + + /** * Returns basic information about the status of Universal Profiling. * diff --git a/src/Endpoints/Security.php b/src/Endpoints/Security.php index 2d148e9d8..3e570591a 100644 --- a/src/Endpoints/Security.php +++ b/src/Endpoints/Security.php @@ -1763,6 +1763,41 @@ public function queryApiKeys(array $params = []) } + /** + * Retrieves information for Users using a subset of query DSL + * + * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-query-user.html + * + * @param array{ + * with_profile_uid: boolean, // flag to retrieve profile uid (if exists) associated with the user + * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) + * human: boolean, // Return human readable values for statistics. (DEFAULT: true) + * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) + * source: string, // The URL-encoded request definition. Useful for libraries that do not accept a request body for non-POST requests. + * filter_path: list, // A comma-separated list of filters used to reduce the response. + * body: array, // From, size, query, sort and search_after + * } $params + * + * @throws NoNodeAvailableException if all the hosts are offline + * @throws ClientResponseException if the status code of response is 4xx + * @throws ServerResponseException if the status code of response is 5xx + * + * @return Elasticsearch|Promise + */ + public function queryUser(array $params = []) + { + $url = '/_security/_query/user'; + $method = empty($params['body']) ? 'GET' : 'POST'; + + $url = $this->addQueryString($url, $params, ['with_profile_uid','pretty','human','error_trace','source','filter_path']); + $headers = [ + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + ]; + return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); + } + + /** * Exchanges a SAML Response message for an Elasticsearch access token and refresh token pair * diff --git a/src/Endpoints/Synonyms.php b/src/Endpoints/Synonyms.php index 2256b4f09..a99f30aff 100644 --- a/src/Endpoints/Synonyms.php +++ b/src/Endpoints/Synonyms.php @@ -32,7 +32,6 @@ class Synonyms extends AbstractEndpoint * Deletes a synonym set * * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/delete-synonyms-set.html - * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release * * @param array{ * id: string, // (REQUIRED) The id of the synonyms set to be deleted @@ -68,7 +67,6 @@ public function deleteSynonym(array $params = []) * Deletes a synonym rule in a synonym set * * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/delete-synonym-rule.html - * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release * * @param array{ * set_id: string, // (REQUIRED) The id of the synonym set to be updated @@ -106,7 +104,6 @@ public function deleteSynonymRule(array $params = []) * Retrieves a synonym set * * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/get-synonyms-set.html - * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release * * @param array{ * id: string, // (REQUIRED) The name of the synonyms set to be retrieved @@ -144,7 +141,6 @@ public function getSynonym(array $params = []) * Retrieves a synonym rule from a synonym set * * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/get-synonym-rule.html - * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release * * @param array{ * set_id: string, // (REQUIRED) The id of the synonym set to retrieve the synonym rule from @@ -182,7 +178,6 @@ public function getSynonymRule(array $params = []) * Retrieves a summary of all defined synonym sets * * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/list-synonyms-sets.html - * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release * * @param array{ * from: int, // Starting offset @@ -217,7 +212,6 @@ public function getSynonymsSets(array $params = []) * Creates or updates a synonyms set * * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/put-synonyms-set.html - * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release * * @param array{ * id: string, // (REQUIRED) The id of the synonyms set to be created or updated @@ -255,7 +249,6 @@ public function putSynonym(array $params = []) * Creates or updates a synonym rule in a synonym set * * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/put-synonym-rule.html - * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release * * @param array{ * set_id: string, // (REQUIRED) The id of the synonym set to be updated with the synonym rule diff --git a/src/Endpoints/TextStructure.php b/src/Endpoints/TextStructure.php index db65e57a8..d90f2e6a3 100644 --- a/src/Endpoints/TextStructure.php +++ b/src/Endpoints/TextStructure.php @@ -76,4 +76,40 @@ public function findStructure(array $params = []) ]; return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); } + + + /** + * Tests a Grok pattern on some text. + * + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/test-grok-pattern.html + * + * @param array{ + * ecs_compatibility: string, // Optional parameter to specify the compatibility mode with ECS Grok patterns - may be either 'v1' or 'disabled' + * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) + * human: boolean, // Return human readable values for statistics. (DEFAULT: true) + * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) + * source: string, // The URL-encoded request definition. Useful for libraries that do not accept a request body for non-POST requests. + * filter_path: list, // A comma-separated list of filters used to reduce the response. + * body: array, // (REQUIRED) The Grok pattern and text. + * } $params + * + * @throws NoNodeAvailableException if all the hosts are offline + * @throws ClientResponseException if the status code of response is 4xx + * @throws ServerResponseException if the status code of response is 5xx + * + * @return Elasticsearch|Promise + */ + public function testGrokPattern(array $params = []) + { + $this->checkRequiredParameters(['body'], $params); + $url = '/_text_structure/test_grok_pattern'; + $method = empty($params['body']) ? 'GET' : 'POST'; + + $url = $this->addQueryString($url, $params, ['ecs_compatibility','pretty','human','error_trace','source','filter_path']); + $headers = [ + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + ]; + return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); + } } diff --git a/src/Traits/ClientEndpointsTrait.php b/src/Traits/ClientEndpointsTrait.php index c4b55beed..7a850486f 100644 --- a/src/Traits/ClientEndpointsTrait.php +++ b/src/Traits/ClientEndpointsTrait.php @@ -45,6 +45,7 @@ trait ClientEndpointsTrait * _source_includes: list, // Default list of fields to extract and return from the _source field, can be overridden on each sub-request * pipeline: string, // The pipeline id to preprocess incoming documents with * require_alias: boolean, // Sets require_alias for all incoming documents. Defaults to unset (false) + * require_data_stream: boolean, // When true, requires the destination to be a data stream (existing or to-be-created). Default is false * list_executed_pipelines: boolean, // Sets list_executed_pipelines for all incoming documents. Defaults to unset (false) * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) * human: boolean, // Return human readable values for statistics. (DEFAULT: true) @@ -70,7 +71,7 @@ public function bulk(array $params = []) $url = '/_bulk'; $method = 'POST'; } - $url = $this->addQueryString($url, $params, ['wait_for_active_shards','refresh','routing','timeout','type','_source','_source_excludes','_source_includes','pipeline','require_alias','list_executed_pipelines','pretty','human','error_trace','source','filter_path']); + $url = $this->addQueryString($url, $params, ['wait_for_active_shards','refresh','routing','timeout','type','_source','_source_excludes','_source_includes','pipeline','require_alias','require_data_stream','list_executed_pipelines','pretty','human','error_trace','source','filter_path']); $headers = [ 'Accept' => 'application/json', 'Content-Type' => 'application/x-ndjson', @@ -590,6 +591,7 @@ public function explain(array $params = []) * include_unmapped: boolean, // Indicates whether unmapped fields should be included in the response. * filters: list, // An optional set of filters: can include +metadata,-metadata,-nested,-multifield,-parent * types: list, // Only return results for fields that have one of the types in the list + * include_empty_fields: boolean, // Include empty fields in result * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) * human: boolean, // Return human readable values for statistics. (DEFAULT: true) * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) @@ -613,7 +615,7 @@ public function fieldCaps(array $params = []) $url = '/_field_caps'; $method = empty($params['body']) ? 'GET' : 'POST'; } - $url = $this->addQueryString($url, $params, ['fields','ignore_unavailable','allow_no_indices','expand_wildcards','include_unmapped','filters','types','pretty','human','error_trace','source','filter_path']); + $url = $this->addQueryString($url, $params, ['fields','ignore_unavailable','allow_no_indices','expand_wildcards','include_unmapped','filters','types','include_empty_fields','pretty','human','error_trace','source','filter_path']); $headers = [ 'Accept' => 'application/json', 'Content-Type' => 'application/json', @@ -873,6 +875,7 @@ public function healthReport(array $params = []) * if_primary_term: number, // only perform the index operation if the last operation that has changed the document has the specified primary term * pipeline: string, // The pipeline id to preprocess incoming documents with * require_alias: boolean, // When true, requires destination to be an alias. Default is false + * require_data_stream: boolean, // When true, requires the destination to be a data stream (existing or to-be-created). Default is false * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) * human: boolean, // Return human readable values for statistics. (DEFAULT: true) * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) @@ -898,7 +901,7 @@ public function index(array $params = []) $url = '/' . $this->encode($params['index']) . '/_doc'; $method = 'POST'; } - $url = $this->addQueryString($url, $params, ['wait_for_active_shards','op_type','refresh','routing','timeout','version','version_type','if_seq_no','if_primary_term','pipeline','require_alias','pretty','human','error_trace','source','filter_path']); + $url = $this->addQueryString($url, $params, ['wait_for_active_shards','op_type','refresh','routing','timeout','version','version_type','if_seq_no','if_primary_term','pipeline','require_alias','require_data_stream','pretty','human','error_trace','source','filter_path']); $headers = [ 'Accept' => 'application/json', 'Content-Type' => 'application/json', From 5812ed5dbae3444175411d11b2cbedcb28f9a362 Mon Sep 17 00:00:00 2001 From: Enrico Zimuel Date: Wed, 27 Mar 2024 10:50:42 +0100 Subject: [PATCH 5/7] Fixed profiling tests + skipped tests --- src/Endpoints/Profiling.php | 2 ++ util/YamlTests.php | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Endpoints/Profiling.php b/src/Endpoints/Profiling.php index fb15418f6..b7f94189b 100644 --- a/src/Endpoints/Profiling.php +++ b/src/Endpoints/Profiling.php @@ -57,6 +57,7 @@ public function flamegraph(array $params = []) $url = $this->addQueryString($url, $params, ['pretty','human','error_trace','source','filter_path']); $headers = [ 'Accept' => 'application/json', + 'Content-Type' => 'application/json' ]; return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); } @@ -91,6 +92,7 @@ public function stacktraces(array $params = []) $url = $this->addQueryString($url, $params, ['pretty','human','error_trace','source','filter_path']); $headers = [ 'Accept' => 'application/json', + 'Content-Type' => 'application/json' ]; return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); } diff --git a/util/YamlTests.php b/util/YamlTests.php index 5cef31bf8..b544cf38e 100644 --- a/util/YamlTests.php +++ b/util/YamlTests.php @@ -39,7 +39,8 @@ class YamlTests 'free/cluster.desired_nodes/20_dry_run.yml', 'free/health/', 'free/cluster.desired_balance/10_basic.yml', - 'free/cluster.prevalidate_node_removal/10_basic.yml' + 'free/cluster.prevalidate_node_removal/10_basic.yml', + 'free/cluster.desired_nodes/11_old_format.yml' ]; const SKIPPED_TEST_OSS = [ @@ -55,6 +56,7 @@ class YamlTests 'Indices\GetIndexTemplate\_10_BasicTest::*' => 'Bool mismatch', 'Indices\PutTemplate\_10_BasicTest::PutTemplateCreate' => 'index_template [test] already exists', 'Indices\Refresh\_10_BasicTest::IndicesRefreshTestEmptyArray' => 'empty array?', + 'Indices\ResolveCluster\_10_Basic_Resolve_ClusterTest::TestResolveClusterOptionalParamsAreAccepted' => 'Bool mismatch', 'Indices\SimulateIndexTemplate\_10_BasicTest::SimulateIndexTemplateWithIndexNotMatchingAnyTemplate' => 'Bool mismatch', 'Search\Vectors\_90_Sparse_VectorTest::SparseVectorIn800X8110' => 'Undefined array key error', 'Snapshot\Create\_10_BasicTest::CreateASnapshot' => 'Invalid snapshot name [test_snapshot]', @@ -66,6 +68,7 @@ class YamlTests 'ApiKey\_10_BasicTest::TestGetApiKey' => 'Mismatch values', 'ApiKey\_20_QueryTest::TestQueryApiKey' => 'Mismatch values', 'DataStream\_80_Resolve_Index_Data_StreamsTest::*' => 'Skipped all tests', + 'Dlm\_10_UsageTest::TestDataStreamLifecycleUsageStats' => 'Mismatch values', 'Esql\_30_TypesTest::Unsigned_long' => 'Format number issue', 'Health\_10_UsageTest::UsageStatsOnTheHealthAPI' => 'Undefined array key \"green\"', 'License\_20_Put_LicenseTest::*' => 'License issue', @@ -105,6 +108,7 @@ class YamlTests 'Token\_10_BasicTest::TestInvalidateRealmsTokens' => 'Mismatch values', 'Transform\_Transforms_CrudTest::TestDeleteTransformWhenItDoesNotExist' => 'Invalid version format: TRANSFORM HTTP/1.1', 'UnsignedLong\*' => 'Skipped all tests', + 'Users\_40_QueryTest::TestQueryUser' => 'Mismatch values', 'Vectors\_30_Sparse_Vector_BasicTest::DeprecatedFunctionSignature' => 'Failed asserting contains string', ]; From 6280c6439dc4bf49ad0333594e6e6162e37a95ec Mon Sep 17 00:00:00 2001 From: Enrico Zimuel Date: Wed, 27 Mar 2024 14:58:18 +0100 Subject: [PATCH 6/7] FIxed RestSpecRunnner with build_id for rest-resource --- util/RestSpecRunner.php | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/util/RestSpecRunner.php b/util/RestSpecRunner.php index 121c68790..8f749c0ad 100644 --- a/util/RestSpecRunner.php +++ b/util/RestSpecRunner.php @@ -39,7 +39,8 @@ $version = $serverInfo['version']['number']; $artifactFile = sprintf("rest-resources-zip-%s.zip", $version); -$tempFilePath = sprintf("%s/%s.zip", sys_get_temp_dir(), $serverInfo['version']['build_hash']); +$buildHash = $serverInfo['version']['build_hash']; +$tempFilePath = sprintf("%s/%s.zip", sys_get_temp_dir(), $buildHash); if (!file_exists($tempFilePath)) { // Download of Elasticsearch rest-api artifacts @@ -49,28 +50,37 @@ exit(1); } $content = json_decode($json, true); + $found = false; foreach ($content['version']['builds'] as $builds) { - if ($builds['projects']['elasticsearch']['commit_hash'] === $serverInfo['version']['build_hash']) { + if ($builds['projects']['elasticsearch']['commit_hash'] === $buildHash) { // Download the artifact ZIP file (rest-resources-zip-$version.zip) printf("Download %s\n", $builds['projects']['elasticsearch']['packages'][$artifactFile]['url']); if (!copy($builds['projects']['elasticsearch']['packages'][$artifactFile]['url'], $tempFilePath)) { printf ("ERROR: failed to download %s\n", $artifactFile); } + $found = true; break; } } + if (!$found) { + $build = $content['version']['builds'][0]; // pick the most recent + $resource = $build["projects"]["elasticsearch"]["packages"][sprintf("rest-resources-zip-%s.zip", $version)]['url']; + if (!copy($resource, $tempFilePath)) { + printf ("ERROR: failed to download %s\n", $resource); + } + } } else { printf("The file %s already exists\n", $tempFilePath); } if (!file_exists($tempFilePath)) { - printf("ERROR: the commit_hash %s has not been found\n", $serverInfo['version']['build_hash']); + printf("ERROR: I cannot download file %s\n", $tempFilePath); exit(1); } $zip = new ZipArchive(); $zip->open($tempFilePath); -printf("Extracting %s\ninto %s/rest-spec/%s\n", $tempFilePath, __DIR__, $serverInfo['version']['build_hash']); -$zip->extractTo(sprintf("%s/rest-spec/%s", __DIR__, $serverInfo['version']['build_hash'])); +printf("Extracting %s\ninto %s/rest-spec/%s\n", $tempFilePath, __DIR__, $buildHash); +$zip->extractTo(sprintf("%s/rest-spec/%s", __DIR__, $buildHash)); $zip->close(); printf ("Rest-spec API installed successfully!\n\n"); \ No newline at end of file From 221723e9497515ec82833995a97c8546d9b6499a Mon Sep 17 00:00:00 2001 From: Enrico Zimuel Date: Wed, 27 Mar 2024 16:09:06 +0100 Subject: [PATCH 7/7] Prep for 8.13.0 release --- CHANGELOG.md | 83 +++++++++++++++++++++++++++++++++++++ docs/release-notes.asciidoc | 14 ++++++- src/Client.php | 2 +- 3 files changed, 96 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 438b50d9e..fcfd65895 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,86 @@ +## Release 8.13.0 + +- Added the `mapTo($class)` function to Elasticsearch response for mapping the result + of [ES|QL](https://www.elastic.co/guide/en/elasticsearch/reference/current/esql.html) + query to an object of stdClass or of a specific class + [#1398](https://github.com/elastic/elasticsearch-php/issues/1398) + +This release introduces 6 new APIs and 6 EXPERIMENTAL APIs. + +- Specific changes per endpoints + - `AsyncSearch.status` + - Added the `keep_alive` parameter (time), specify the time interval in which the results (partial or final) for this search will be available. + - `Connector.list` + - Added the following parameters: + - `index_name`: list, a comma-separated list of connector index names to fetch connector documents for; + - `connector_name`: list, a comma-separated list of connector names to fetch connector documents for; + - `service_type`: list, a comma-separated list of connector service types to fetch connector documents for; + - `query`: string, a search string for querying connectors, filtering results by matching against connector names, descriptions, and index names; + - `Connector.updateApiKeyId` (new EXPERIMENTAL API) + - API: https://github.com/elastic/elasticsearch/blob/main/rest-api-spec/src/main/resources/rest-api-spec/api/connector.update_api_key_id.json + - Documentation: https://www.elastic.co/guide/en/elasticsearch/reference/master/update-connector-api-key-id-api.html + - `Connector.updateIndexName` (new EXPERIMENTAL API) + - API: https://github.com/elastic/elasticsearch/blob/main/rest-api-spec/src/main/resources/rest-api-spec/api/connector.update_index_name.json + - Documentation: https://www.elastic.co/guide/en/elasticsearch/reference/master/update-connector-index-name-api.html + - `Connector.updateNative` (new EXPERIMENTAL API) + - API: https://github.com/elastic/elasticsearch/blob/main/rest-api-spec/src/main/resources/rest-api-spec/api/connector.update_native.json + - Documentation: https://www.elastic.co/guide/en/elasticsearch/reference/master/connector-apis.html + - `Connector.updateServiceType` (new EXPERIMENTAL API) + - API: https://github.com/elastic/elasticsearch/blob/main/rest-api-spec/src/main/resources/rest-api-spec/api/connector.update_service_type.json + - Documentation: https://www.elastic.co/guide/en/elasticsearch/reference/master/update-connector-service-type-api.html + - `Connector.updateStatus` (new EXPERIMENTAL API) + - API: https://github.com/elastic/elasticsearch/blob/main/rest-api-spec/src/main/resources/rest-api-spec/api/connector.update_status.json + - Documentation: https://www.elastic.co/guide/en/elasticsearch/reference/master/update-connector-status-api.html + - `ConnectorSyncJob.list` + - Added the `job_type` parameter (list), a comma-separated list of job types. + - `Esql.asyncQuery` (new EXPERIMENTAL API) + - API: https://github.com/elastic/elasticsearch/blob/main/rest-api-spec/src/main/resources/rest-api-spec/api/esql.async_query.json + - Documentation: https://www.elastic.co/guide/en/elasticsearch/reference/master/esql-async-query-api.html + - `Esql.asyncQueryGet` (new API) + - API: https://github.com/elastic/elasticsearch/blob/main/rest-api-spec/src/main/resources/rest-api-spec/api/esql.async_query_get.json + - Documentation: https://www.elastic.co/guide/en/elasticsearch/reference/master/esql-async-query-get-api.html + - `Esql.query` + - Added the `drop_null_columns` parameter (boolean) to sepcify if null columns should be removed from the results. If yes, their name and type will be returned in a new `all_columns` section. + - `Indices.resolveCluster` (new API) + - API: https://github.com/elastic/elasticsearch/blob/main/rest-api-spec/src/main/resources/rest-api-spec/api/get_script.json + - Documentation: https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-resolve-cluster-api.html + - `Indices.rollover` + - Added the `lazy` parameter (boolean), if set to true, the rollover action will only mark a data stream to signal that it needs to be rolled over at the next write. Only allowed on data streams. + - `Inference.deleteModel` + - The `model_id` parameter has been renamed to `inference_id`. + - `Inference.getModel` + - The `model_id` parameter has been renamed in `inference_id`. + - `Inference.inference` + - The `model_id` parameter has been renamed in `inference_id`. + - `Inference.putModel` + - The `model_id` parameter has been renamed in `inference_id`. + - `Profiling.flamegraph` (new API) + - API: https://github.com/elastic/elasticsearch/blob/main/rest-api-spec/src/main/resources/rest-api-spec/api/profiling.flamegraph.json + - Documentation: https://www.elastic.co/guide/en/observability/current/universal-profiling.html + - `Profiling.stacktraces` (new API) + - API: https://github.com/elastic/elasticsearch/blob/main/rest-api-spec/src/main/resources/rest-api-spec/api/profiling.stacktraces.json + - Documentation: https://www.elastic.co/guide/en/observability/current/universal-profiling.html + - `Security.queryUser` (new API) + - API: https://github.com/elastic/elasticsearch/blob/main/rest-api-spec/src/main/resources/rest-api-spec/api/security.query_user.json + - Documentation: https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-query-user.html + - `Synonyms.deleteSynonym` + - This API is now stable. + - `Synonyms.deleteSynonymRule` + - This API is now stable. + - `Synonyms.getSynonym` + - This API is now stable. + - `Synonyms.getSynonymRule` + - This API is now stable. + - `Synonyms.getSynonymsSets` + - This API is now stable. + - `Synonyms.putSynonym` + - This API is now stable. + - `Synonyms.putSynonymRule` + - This API is now stable. + - `TextStructure.testGrokPattern` (new API) + - API: https://github.com/elastic/elasticsearch/blob/main/rest-api-spec/src/main/resources/rest-api-spec/api/text_structure.test_grok_pattern.json + - Documentation: https://www.elastic.co/guide/en/elasticsearch/reference/master/test-grok-pattern.html + ## Release 8.12.0 - Added 22 new EXPERIMENTAL APIs and 1 new stable API: diff --git a/docs/release-notes.asciidoc b/docs/release-notes.asciidoc index dca64f9d9..e48ba07c8 100644 --- a/docs/release-notes.asciidoc +++ b/docs/release-notes.asciidoc @@ -1,7 +1,8 @@ [[release-notes]] == Release notes -* <> +* <> +* <> * <> * <> * <> @@ -44,11 +45,20 @@ * <> * <> +[discrete] +[[rn-8-13-0]] +=== 8.13.0 + +* Updated the API endpoints to Elasticserach 8.13.0 +* Added the Added the mapTo($class) function to Elasticsearch response for mapping the result + of https://www.elastic.co/guide/en/elasticsearch/reference/current/esql.html[ES|QL] + query to an object of stdClass or a specific class https://github.com/elastic/elasticsearch-php/issues/1398[#1398] + [discrete] [[rn-8-12-0]] === 8.12.0 -* Updated the API endpoints to Elasticserach 8.11.0 +* Updated the API endpoints to Elasticserach 8.12.0 * Tested the library with PHP 8.3 [discrete] diff --git a/src/Client.php b/src/Client.php index d7063596f..148135a9c 100644 --- a/src/Client.php +++ b/src/Client.php @@ -28,7 +28,7 @@ final class Client implements ClientInterface { const CLIENT_NAME = 'es'; - const VERSION = '8.12.0'; + const VERSION = '8.13.0'; const API_COMPATIBILITY_HEADER = '%s/vnd.elasticsearch+%s; compatible-with=8'; use ClientEndpointsTrait;