Skip to content

Release 9.0 #8485

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Apr 11, 2025
Merged
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .buildkite/DockerFile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARG DOTNET_VERSION=8.0.400
ARG DOTNET_VERSION=9.0.100
FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION} AS elasticsearch-net-build

ENV NUGET_SCRATCH="/tmp/NuGetScratch"
2 changes: 1 addition & 1 deletion .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ steps:
env:
TEST_SUITE: "{{ matrix.suite }}"
STACK_VERSION: master-SNAPSHOT
DOTNET_VERSION: 8.0.400
DOTNET_VERSION: 9.0.100
matrix:
setup:
suite:
2 changes: 1 addition & 1 deletion .buildkite/run-repository.ps1
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ param(
$NODE_NAME,

[string]
$DOTNET_VERSION = "8.0.400"
$DOTNET_VERSION = "9.0.100"
)

$ESC = [char]27
2 changes: 1 addition & 1 deletion .buildkite/run-repository.sh
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ script_path=$(dirname $(realpath -s $0))
source $script_path/functions/imports.sh
set -euo pipefail

DOTNET_VERSION=${DOTNET_VERSION-8.0.400}
DOTNET_VERSION=${DOTNET_VERSION-9.0.100}
ELASTICSEARCH_URL=${ELASTICSEARCH_URL-"$elasticsearch_url"}
elasticsearch_container=${elasticsearch_container-}

2 changes: 1 addition & 1 deletion .buildkite/run-tests.ps1
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ param (
$TEST_SUITE = "free",

[string]
$DOTNET_VERSION = "8.0.400"
$DOTNET_VERSION = "9.0.100"
)

$ESC = [char]27
2 changes: 1 addition & 1 deletion .ci/DockerFile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARG DOTNET_VERSION=8.0.400
ARG DOTNET_VERSION=9.0.100
FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION} AS elasticsearch-net-build

ENV NUGET_SCRATCH="/tmp/NuGetScratch"
2 changes: 1 addition & 1 deletion .ci/make.sh
Original file line number Diff line number Diff line change
@@ -42,7 +42,7 @@ OUTPUT_DIR="$repo/${output_folder}"
REPO_BINDING="${OUTPUT_DIR}:/sln/${output_folder}"
mkdir -p "$OUTPUT_DIR"

DOTNET_VERSION=${DOTNET_VERSION-8.0.400}
DOTNET_VERSION=${DOTNET_VERSION-9.0.100}

echo -e "\033[34;1mINFO:\033[0m PRODUCT ${product}\033[0m"
echo -e "\033[34;1mINFO:\033[0m VERSION ${STACK_VERSION}\033[0m"
2 changes: 1 addition & 1 deletion .ci/readme.md
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ $ STACK_VERSION=8.0.0-SNAPSHOT ./.ci/run-tests
|-------------------------|-------------|-------------|
| `STACK_VERSION` | `N/A` | The elasticsearch version to target
| `TEST_SUITE` | `basic` | `free` or `platinum` sets which test suite to run and which container to run against. |
| `DOTNET_VERSION` | `8.0.400` | The .NET sdk version used to grab the proper container |
| `DOTNET_VERSION` | `9.0.100` | The .NET sdk version used to grab the proper container |

If you want to manually spin up elasticsearch for these tests and call the runner afterwards you can use

2 changes: 1 addition & 1 deletion .ci/run-repository.ps1
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ param(
$NODE_NAME,

[string]
$DOTNET_VERSION = "8.0.400"
$DOTNET_VERSION = "9.0.100"
)

$ESC = [char]27
2 changes: 1 addition & 1 deletion .ci/run-repository.sh
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ script_path=$(dirname $(realpath -s $0))
source $script_path/functions/imports.sh
set -euo pipefail

DOTNET_VERSION=${DOTNET_VERSION-8.0.400}
DOTNET_VERSION=${DOTNET_VERSION-9.0.100}
ELASTICSEARCH_URL=${ELASTICSEARCH_URL-"$elasticsearch_url"}
elasticsearch_container=${elasticsearch_container-}

2 changes: 1 addition & 1 deletion .ci/run-tests.ps1
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ param (
$TEST_SUITE = "free",

[string]
$DOTNET_VERSION = "8.0.400"
$DOTNET_VERSION = "9.0.100"
)

$ESC = [char]27
2 changes: 1 addition & 1 deletion .ci/test-matrix.yml
Original file line number Diff line number Diff line change
@@ -8,6 +8,6 @@ TEST_SUITE:
- platinum

DOTNET_VERSION:
- 8.0.400
- 9.0.100

exclude: ~
4 changes: 4 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -50,4 +50,8 @@
<ItemGroup>
<PackageReference Include="DotNet.ReproducibleBuilds" Version="1.1.1" PrivateAssets="All"/>
</ItemGroup>

<PropertyGroup>
<WarningsNotAsErrors>NU1901;NU1902;NU1903;NU1904</WarningsNotAsErrors>
</PropertyGroup>
</Project>
7 changes: 0 additions & 7 deletions Elasticsearch.sln
Original file line number Diff line number Diff line change
@@ -55,8 +55,6 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "scripts", "build\scripts\sc
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests.ClusterLauncher", "tests\Tests.ClusterLauncher\Tests.ClusterLauncher.csproj", "{F6162603-D134-4121-8106-2BA4DAD7350B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elastic.Clients.Elasticsearch.JsonNetSerializer", "src\Elastic.Clients.Elasticsearch.JsonNetSerializer\Elastic.Clients.Elasticsearch.JsonNetSerializer.csproj", "{8C9275D9-29CE-4A20-8FD5-6B26C6CAAADB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "tests\Tests\Tests.csproj", "{6FD804B2-CE80-41CB-A411-2023F34C18FE}"
EndProject
Global
@@ -101,10 +99,6 @@ Global
{F6162603-D134-4121-8106-2BA4DAD7350B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F6162603-D134-4121-8106-2BA4DAD7350B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F6162603-D134-4121-8106-2BA4DAD7350B}.Release|Any CPU.Build.0 = Release|Any CPU
{8C9275D9-29CE-4A20-8FD5-6B26C6CAAADB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8C9275D9-29CE-4A20-8FD5-6B26C6CAAADB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8C9275D9-29CE-4A20-8FD5-6B26C6CAAADB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8C9275D9-29CE-4A20-8FD5-6B26C6CAAADB}.Release|Any CPU.Build.0 = Release|Any CPU
{6FD804B2-CE80-41CB-A411-2023F34C18FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6FD804B2-CE80-41CB-A411-2023F34C18FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FD804B2-CE80-41CB-A411-2023F34C18FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -123,7 +117,6 @@ Global
{F8A7E60C-0C48-4D76-AF7F-7881DF5A263D} = {D455EC79-E1E0-4509-B297-0DA3AED8DFF7}
{68D1BFDC-F447-4D2C-AF81-537807636610} = {1FE49D14-216A-41EE-A177-E42BFF53E0DC}
{F6162603-D134-4121-8106-2BA4DAD7350B} = {362B2776-4B29-46AB-B237-56776B5372B6}
{8C9275D9-29CE-4A20-8FD5-6B26C6CAAADB} = {D455EC79-E1E0-4509-B297-0DA3AED8DFF7}
{6FD804B2-CE80-41CB-A411-2023F34C18FE} = {362B2776-4B29-46AB-B237-56776B5372B6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
2 changes: 1 addition & 1 deletion build/scripts/Versioning.fs
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ module Versioning =
// Since that file is now generated by the dotnet tooling and GitVersion and similar tooling all still have
// active issues related to dotnet core, we now just burn this info in global.json

let parse (v:string) = SemVer.parse(v)
let parse (v: string) = SemVer.parse(if String.IsNullOrEmpty(v) then "1.0.0" else v)

//Versions in form of e.g 6.1.0 is inferred as datetime so we bake the json shape into the provider like this
type SdkVersion = { version:string; rollForward:string; allowPrerelease:bool }
2 changes: 1 addition & 1 deletion build/scripts/scripts.fsproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<OutputType>Exe</OutputType>
<!-- Type Providers are restored using net461, fine for netcoreapp2.2 so we kill the warning -->
<NoWarn>$(NoWarn);NU1701</NoWarn>
206 changes: 196 additions & 10 deletions docs/release-notes/breaking-changes.md
Original file line number Diff line number Diff line change
@@ -5,22 +5,208 @@
---

# Elasticsearch .NET Client breaking changes [elasticsearch-net-client-breaking-changes]

Breaking changes can impact your Elastic applications, potentially disrupting normal operations. Before you upgrade, carefully review the Elasticsearch .NET Client breaking changes and take the necessary steps to mitigate any issues. To learn how to upgrade, check [Upgrade](docs-content://deploy-manage/upgrade.md).

% ## Next version [elasticsearch-nett-client-nextversion-breaking-changes]
% ## Next version [elasticsearch-net-client-nextversion-breaking-changes]

% ::::{dropdown} Title of breaking change
%
% **Impact**: High/Low.
%
% Description of the breaking change.
% For more information, check [PR #](PR link).
% **Impact**<br> Impact of the breaking change.
% **Action**<br> Steps for mitigating deprecation impact.
%
% ::::

% ## 9.0.0 [elasticsearch-nett-client-900-breaking-changes]
## 9.0.0 [elasticsearch-net-client-900-breaking-changes]

% ::::{dropdown} Title of breaking change
% Description of the breaking change.
% For more information, check [PR #](PR link).
% **Impact**<br> Impact of the breaking change.
% **Action**<br> Steps for mitigating deprecation impact.
% ::::
### Overview

- [1. Container types](#1-container-types)

Check failure on line 26 in docs/release-notes/breaking-changes.md

GitHub Actions / docs-preview / build

`1-container-types` does not exist in release-notes/breaking-changes.md.
- [2. Removal of certain generic request descriptors](#2-removal-of-certain-generic-request-descriptors)

Check failure on line 27 in docs/release-notes/breaking-changes.md

GitHub Actions / docs-preview / build

`2-removal-of-certain-generic-request-descriptors` does not exist in release-notes/breaking-changes.md.
- [3. Removal of certain descriptor constructors and related request APIs](#3-removal-of-certain-descriptor-constructors-and-related-request-apis)

Check failure on line 28 in docs/release-notes/breaking-changes.md

GitHub Actions / docs-preview / build

`3-removal-of-certain-descriptor-constructors-and-related-request-apis` does not exist in release-notes/breaking-changes.md.
- [4. Date / Time / Duration values](#4-date--time--duration-values)

Check failure on line 29 in docs/release-notes/breaking-changes.md

GitHub Actions / docs-preview / build

`4-date--time--duration-values` does not exist in release-notes/breaking-changes.md.
- [5. `ExtendedBounds`](#5-extendedbounds)

Check failure on line 30 in docs/release-notes/breaking-changes.md

GitHub Actions / docs-preview / build

`5-extendedbounds` does not exist in release-notes/breaking-changes.md.
- [6. `Field.Format`](#6-fieldformat)

Check failure on line 31 in docs/release-notes/breaking-changes.md

GitHub Actions / docs-preview / build

`6-fieldformat` does not exist in release-notes/breaking-changes.md.
- [7. `Field`/`Fields` semantics](#7-fieldfields-semantics)

Check failure on line 32 in docs/release-notes/breaking-changes.md

GitHub Actions / docs-preview / build

`7-fieldfields-semantics` does not exist in release-notes/breaking-changes.md.
- [8. `FieldValue`](#8-fieldvalue)

Check failure on line 33 in docs/release-notes/breaking-changes.md

GitHub Actions / docs-preview / build

`8-fieldvalue` does not exist in release-notes/breaking-changes.md.
- [9. `FieldSort`](#9-fieldsort)

Check failure on line 34 in docs/release-notes/breaking-changes.md

GitHub Actions / docs-preview / build

`9-fieldsort` does not exist in release-notes/breaking-changes.md.
- [10. Descriptor types `class` -\> `struct`](#10-descriptor-types-class---struct)

Check failure on line 35 in docs/release-notes/breaking-changes.md

GitHub Actions / docs-preview / build

`10-descriptor-types-class---struct` does not exist in release-notes/breaking-changes.md.

### Breaking changes

#### 1. Container types

**Impact**: High.

Container types now use regular properties for their variants instead of static factory methods ([read more](index.md#7-improved-container-design)).

This change primarily affects the `Query` and `Aggregation` types.

```csharp
// 8.x
new SearchRequest
{
Query = Query.MatchAll(
new MatchAllQuery
{
}
)
};

// 9.0
new SearchRequest
{
Query = new Query
{
MatchAll = new MatchAllQuery
{
}
}
};
```

#### 2. Removal of certain generic request descriptors

**Impact**: High.

Removed the generic version of some request descriptors for which the corresponding requests do not contain inferrable properties.

These descriptors were generated unintentionally.

When migrating, the generic type parameter must be removed from the type, e.g., `AsyncSearchStatusRequestDescriptor<TDocument>` should become just `AsyncSearchStatusRequestDescriptor`.

List of affected descriptors:

- `AsyncQueryDeleteRequestDescriptor<TDocument>`
- `AsyncQueryGetRequestDescriptor<TDocument>`
- `AsyncSearchStatusRequestDescriptor<TDocument>`
- `DatabaseConfigurationDescriptor<TDocument>`
- `DatabaseConfigurationFullDescriptor<TDocument>`
- `DeleteAsyncRequestDescriptor<TDocument>`
- `DeleteAsyncSearchRequestDescriptor<TDocument>`
- `DeleteDataFrameAnalyticsRequestDescriptor<TDocument>`
- `DeleteGeoipDatabaseRequestDescriptor<TDocument>`
- `DeleteIpLocationDatabaseRequestDescriptor<TDocument>`
- `DeleteJobRequestDescriptor<TDocument>`
- `DeletePipelineRequestDescriptor<TDocument>`
- `DeleteScriptRequestDescriptor<TDocument>`
- `DeleteSynonymRequestDescriptor<TDocument>`
- `EqlDeleteRequestDescriptor<TDocument>`
- `EqlGetRequestDescriptor<TDocument>`
- `GetAsyncRequestDescriptor<TDocument>`
- `GetAsyncSearchRequestDescriptor<TDocument>`
- `GetAsyncStatusRequestDescriptor<TDocument>`
- `GetDataFrameAnalyticsRequestDescriptor<TDocument>`
- `GetDataFrameAnalyticsStatsRequestDescriptor<TDocument>`
- `GetEqlStatusRequestDescriptor<TDocument>`
- `GetGeoipDatabaseRequestDescriptor<TDocument>`
- `GetIpLocationDatabaseRequestDescriptor<TDocument>`
- `GetJobsRequestDescriptor<TDocument>`
- `GetPipelineRequestDescriptor<TDocument>`
- `GetRollupCapsRequestDescriptor<TDocument>`
- `GetRollupIndexCapsRequestDescriptor<TDocument>`
- `GetScriptRequestDescriptor<TDocument>`
- `GetSynonymRequestDescriptor<TDocument>`
- `IndexModifyDataStreamActionDescriptor<TDocument>`
- `PreprocessorDescriptor<TDocument>`
- `PutGeoipDatabaseRequestDescriptor<TDocument>`
- `PutIpLocationDatabaseRequestDescriptor<TDocument>`
- `PutScriptRequestDescriptor<TDocument>`
- `PutSynonymRequestDescriptor<TDocument>`
- `QueryVectorBuilderDescriptor<TDocument>`
- `RankDescriptor<TDocument>`
- `RenderSearchTemplateRequestDescriptor<TDocument>`
- `SmoothingModelDescriptor<TDocument>`
- `StartDataFrameAnalyticsRequestDescriptor<TDocument>`
- `StartJobRequestDescriptor<TDocument>`
- `StopDataFrameAnalyticsRequestDescriptor<TDocument>`
- `StopJobRequestDescriptor<TDocument>`
- `TokenizationConfigDescriptor<TDocument>`
- `UpdateDataFrameAnalyticsRequestDescriptor<TDocument>`

#### 3. Removal of certain descriptor constructors and related request APIs

**Impact**: High.

Removed `(TDocument, IndexName)` descriptor constructors and related request APIs for all requests with `IndexName` and `Id` path parameters.

For example:

```csharp
// 8.x
public IndexRequestDescriptor(TDocument document, IndexName index, Id? id) { }
public IndexRequestDescriptor(TDocument document, IndexName index) { }
public IndexRequestDescriptor(TDocument document, Id? id) { }
public IndexRequestDescriptor(TDocument document) { }

// 9.0
public IndexRequestDescriptor(TDocument document, IndexName index, Id? id) { }
public IndexRequestDescriptor(TDocument document, Id? id) { }
public IndexRequestDescriptor(TDocument document) { }
```

These overloads caused invocation ambiguities since both, `IndexName` and `Id` implement implicit conversion operators from `string`.

Alternative with same semantics:

```csharp
// Descriptor constructor.
new IndexRequestDescriptor(document, "my_index", Id.From(document));

// Request API method.
await client.IndexAsync(document, "my_index", Id.From(document), ...);
```

#### 4. Date / Time / Duration values

**Impact**: High.

In places where previously `long` or `double` was used to represent a date/time/duration value, `DateTimeOffset` or `TimeSpan` is now used instead.

#### 5. `ExtendedBounds`

**Impact**: High.

Removed `ExtendedBoundsDate`/`ExtendedBoundsDateDescriptor`, `ExtendedBoundsFloat`/`ExtendedBoundsFloatDescriptor`.

Replaced by `ExtendedBounds<T>`, `ExtendedBoundsOfFieldDateMathDescriptor`, and `ExtendedBoundsOfDoubleDescriptor`.

#### 6. `Field.Format`

**Impact**: Low.

Removed `Field.Format` property and corresponding constructor and inferrer overloads.

This property has not been used for some time (replaced by the `FieldAndFormat` type).

#### 7. `Field`/`Fields` semantics

**Impact**: Low.

`Field`/`Fields` static factory methods and conversion operators no longer return nullable references but throw exceptions instead (`Field`) if the input `string`/`Expression`/`PropertyInfo` argument is `null`.

This makes implicit conversions to `Field` more user-friendly without requiring the null-forgiveness operator (`!`) ([read more](index.md#field-name-inference)).

#### 8. `FieldValue`

**Impact**: Low.

Removed `FieldValue.IsLazyDocument`, `FieldValue.IsComposite`, and the corresponding members in the `FieldValue.ValueKind` enum.

These values have not been used for some time.

#### 9. `FieldSort`

**Impact**: Low.

Removed static `FieldSort.Empty` member.

Sorting got reworked which makes this member obsolete ([read more](index.md#sorting)).

#### 10. Descriptor types `class` -> `struct`

**Impact**: Low.

All descriptor types are now implemented as `struct` instead of `class`.
378 changes: 372 additions & 6 deletions docs/release-notes/index.md
Original file line number Diff line number Diff line change
@@ -6,22 +6,388 @@ mapped_pages:

# Elasticsearch .NET Client release notes [elasticsearch-net-client-release-notes]

Review the changes, fixes, and more in each version of Elasticsearch .NET Client.
Review the changes, fixes, and more in each version of Elasticsearch .NET Client.

To check for security updates, go to [Security announcements for the Elastic stack](https://discuss.elastic.co/c/announcements/security-announcements/31).

% Release notes include only features, enhancements, and fixes. Add breaking changes, deprecations, and known issues to the applicable release notes sections.
% Release notes include only features, enhancements, and fixes. Add breaking changes, deprecations, and known issues to the applicable release notes sections.

% ## version.next [felasticsearch-net-client-next-release-notes]

% ### Features and enhancements [elasticsearch-net-client-next-features-enhancements]
% *
% *

% ### Fixes [elasticsearch-net-client-next-fixes]
% *
% *

## 9.0.0 [elasticsearch-net-client-900-release-notes]

### Features and enhancements [elasticsearch-net-client-900-features-enhancements]
### Overview

### Fixes [elasticsearch-net-client-900-fixes]
- [1. Request Method/API Changes](#1-request-methodapi-changes)
- [1.1. Synchronous Request APIs](#11-synchronous-request-apis)
- [1.2. Separate Type Arguments for Request/Response](#12-separate-type-arguments-for-requestresponse)
- [2. Improved Fluent API](#2-improved-fluent-api)
- [2.1. `ICollection<E>`](#21-icollectione)
- [2.2. `IDictionary<K, V>`](#22-idictionaryk-v)
- [2.3. `ICollection<KeyValuePair<K, V>>`](#23-icollectionkeyvaluepairk-v)
- [2.4. Union Types](#24-union-types)
- [3. Improved Descriptor Design](#3-improved-descriptor-design)
- [3.1. Wrap](#31-wrap)
- [3.2. Unwrap / Inspect](#32-unwrap--inspect)
- [3.3. Removal of Side Effects](#33-removal-of-side-effects)
- [4. Request Path Parameter Properties](#4-request-path-parameter-properties)
- [5. Field Name Inference](#5-field-name-inference)
- [6. Uniform Date/Time/Duration Types](#6-uniform-datetimeduration-types)
- [7. Improved Container Design](#7-improved-container-design)
- [8. Sorting](#8-sorting)
- [9. Safer Object Creation](#9-safer-object-creation)
- [10. Serialization](#10-serialization)

### Features and enhancements

#### 1. Request Method/API Changes

##### 1.1. Synchronous Request APIs

Synchronous request APIs are no longer marked as `obsolete`. We received some feedback about this deprecation and decided to revert it.

##### 1.2. Separate Type Arguments for Request/Response

It is now possible to specify separate type arguments for requests/responses when executing request methods:

```csharp
var response = await client.SearchAsync<Person, JsonObject>(x => x
.Query(x => x.Term(x => x.Field(x => x.FirstName).Value("Florian")))
);

var documents = response.Documents; <1>
```

1. `IReadOnlyCollection<JsonObject>`

The regular APIs with merged type arguments are still available.

#### 2. Improved Fluent API

The enhanced fluent API generation is likely the most notable change in the 9.0 client.

This section describes the main syntax constructs generated based on the type of the property in the corresponding object.

##### 2.1. `ICollection<E>`

Note: This syntax already existed in 8.x.

```csharp
new SearchRequestDescriptor<Person>()
.Query(q => q
.Bool(b => b
.Must(new Query()) // Scalar: Single element.
.Must(new Query(), new Query()) // Scalar: Multiple elements (params).
.Must(m => m.MatchAll()) // Fluent: Single element.
.Must(m => m.MatchAll(), m => m.MatchNone()) // Fluent: Multiple elements (params).
)
);
```

##### 2.2. `IDictionary<K, V>`

The 9.0 client introduces full fluent API support for dictionary types.

```csharp
new SearchRequestDescriptor<Person>()
.Aggregations(new Dictionary<string, Aggregation>()) // Scalar.
.Aggregations(aggs => aggs // Fluent: Nested.
.Add("key", new MaxAggregation()) // Scalar: Key + Value.
.Add("key", x => x.Max()) // Fluent: Key + Value.
)
.AddAggregation("key", new MaxAggregation()) // Scalar.
.AddAggregation("key", x => x.Max()); // Fluent.
```

:::{warning}

The `Add{Element}` methods have different semantics compared to the standard setter methods.

Standard fluent setters set or **replace** a value.

In contrast, the new additive methods append new elements to the dictionary.

:::

For dictionaries where the value type does not contain required properties that must be initialized, another syntax is generated that allows easy addition of new entries by just specifying the key:

```csharp
// Dictionary<Name, Alias>()
new CreateIndexRequestDescriptor("index")
// ... all previous overloads ...
.Aliases(aliases => aliases // Fluent: Nested.
.Add("key") // Key only.
)
.Aliases("key") // Key only: Single element.
.Aliases("first", "second") // Key only: Multiple elements (params).
```

If the value type in the dictionary is a collection, additional `params` overloads are generated:

```csharp
// Dictionary<Field, ICollection<CompletionContext>>
new CompletionSuggesterDescriptor<Person>()
// ... all previous overloads ...
.AddContext("key",
new CompletionContext{ Context = new Context("first") },
new CompletionContext{ Context = new Context("second") }
)
.AddContext("key",
x => x.Context(x => x.Category("first")),
x => x.Context(x => x.Category("second"))
);
```

##### 2.3. `ICollection<KeyValuePair<K, V>>`

Elasticsearch often uses `ICollection<KeyValuePair<K, V>>` types for ordered dictionaries.

The 9.0 client abstracts this implementation detail by providing a fluent API that can be used exactly like the one for `IDictionary<K, V>` types:

```csharp
new PutMappingRequestDescriptor<Person>("index")
.DynamicTemplates(new List<KeyValuePair<string, DynamicTemplate>>()) // Scalar.
.DynamicTemplates(x => x // Fluent: Nested.
.Add("key", new DynamicTemplate()) // Scalar: Key + Value.
.Add("key", x => x.Mapping(new TextProperty())) // Fluent: Key + Value.
)
.AddDynamicTemplate("key", new DynamicTemplate()) // Scalar: Key + Value.
.AddDynamicTemplate("key", x => x.Runtime(x => x.Format("123"))); // Fluent: Key + Value.
```

##### 2.4. Union Types

Fluent syntax is now as well available for all auto-generated union- and variant-types.

```csharp
// TermsQueryField : Union<ICollection<FieldValue>, TermsLookup>
new TermsQueryDescriptor()
.Terms(x => x.Value("a", "b", "c")) <1>
.Terms(x => x.Lookup(x => x.Index("index").Id("id"))); <2>
```

1. `ICollection<FieldValue>`
2. `TermsLookup`

#### 3. Improved Descriptor Design

The 9.0 release features a completely overhauled descriptor design.

Descriptors now wrap the object representation. This brings several internal quality-of-life improvements as well as noticeable benefits to end-users.

##### 3.1. Wrap

Use the wrap constructor to create a new descriptor for an existing object:

```csharp
var request = new SearchRequest();

// Wrap.
var descriptor = new SearchRequestDescriptor(request);
```

All fluent methods of the descriptor will mutate the existing `request` passed to the wrap constructor.

:::{note}

Descriptors are now implemented as `struct` instead of `class`, reducing allocation overhead as much as possible.

:::

##### 3.2. Unwrap / Inspect

Descriptor values can now be inspected by unwrapping the object using an implicit conversion operator:

```csharp
var descriptor = new SearchRequestDescriptor();

// Unwrap.
SearchRequest request = descriptor;
```

Unwrapping does not allocate or copy.

##### 3.3. Removal of Side Effects

In 8.x, execution of (most but not all) lambda actions passed to descriptors was deferred until the actual request was made. It was never clear to the user when, and how often an action would be executed.

In 9.0, descriptor actions are always executed immediately. This ensures no unforeseen side effects occur if the user-provided lambda action mutates external state (it is still recommended to exclusively use pure/invariant actions). Consequently, the effects of all changes performed by a descriptor method are immediately applied to the wrapped object.

#### 4. Request Path Parameter Properties

In 8.x, request path parameters like `Index`, `Id`, etc. could only be set by calling the corresponding constructor of the request. Afterwards, there was no way to read or change the current value.

In the 9.0 client, all request path parameters are exposed as `get/set` properties, allowing for easy access:

```csharp
// 8.x and 9.0
var request = new SearchRequest(Indices.All);

// 9.0
var request = new SearchRequest { Indices = Indices.All };
var indices = request.Indices;
request.Indices = "my_index";
```

#### 5. Field Name Inference

The `Field` type and especially its implicit conversion operations allowed for `null` return values. This led to a poor developer experience, as the null-forgiveness operator (`!`) had to be used frequently without good reason.

This is no longer required in 9.0:

```csharp
// 8.x
Field field = "field"!;

// 9.0
Field field = "field";
```

#### 6. Uniform Date/Time/Duration Types

The encoding of date, time and duration values in Elasticsearch often varies depending on the context. In addition to string representations in ISO 8601 and RFC 3339 format (always UTC), also Unix timestamps (in seconds, milliseconds, nanoseconds) or simply seconds, milliseconds, nanoseconds are frequently used.

In 8.x, some date/time values are already mapped as `DateTimeOffset`, but the various non-ISO/RFC representations were not.

9.0 now represents all date/time values uniformly as `DateTimeOffset` and also uses the native `TimeSpan` type for all durations.

:::{note}

There are some places where the Elasticsearch custom date/time/duration types are continued to be used. This is always the case when the type has special semantics and/or offers functionality that goes beyond that of the native date/time/duration types (e.g. `Duration`, `DateMath`).

:::

#### 7. Improved Container Design

In 8.x, container types like `Query` or `Aggregation` had to be initialized using static factory methods.

```csharp
// 8.x
var agg = Aggregation.Max(new MaxAggregation { Field = "my_field" });
```

This made it mandatory to assign the created container to a temporary variable if additional properties of the container (not the contained variant) needed to be set:

```csharp
// 8.x
var agg = Aggregation.Max(new MaxAggregation { Field = "my_field" });
agg.Aggregations ??= new Dictionary<string, Aggregation>();
agg.Aggregations.Add("my_sub_agg", Aggregation.Terms(new TermsAggregation()));
```

Additionally, it was not possible to inspect the contained variant.

In 9.0, each possible container variant is represented as a regular property of the container. This allows for determining and inspecting the contained variant and initializing container properties in one go when using an object initializer:

```csharp
// 9.0
var agg = new Aggregation
{
Max = new MaxAggregation { Field = "my_field" },
Aggregations = new Dictionary<string, Aggregation>
{
{ "my_sub_agg", new Aggregation{ Terms = new TermsAggregation() } }
}
};
```

:::{warning}

A container can still only contain a single variant. Setting multiple variants at once is invalid.

Consecutive assignments of variant properties (e.g., first setting `Max`, then `Min`) will cause the previous variant to be replaced.

:::

#### 8. Sorting

Applying a sort order to a search request using the fluent API is now more convenient:

```csharp
var search = new SearchRequestDescriptor<Person>()
.Sort(
x => x.Score(),
x => x.Score(x => x.Order(SortOrder.Desc)),
x => x.Field(x => x.FirstName),
x => x.Field(x => x.Age, x => x.Order(SortOrder.Desc)),
x => x.Field(x => x.Age, SortOrder.Desc)
// 7.x syntax
x => x.Field(x => x.Field(x => x.FirstName).Order(SortOrder.Desc))
);
```

The improvements are even more evident when specifying a sort order for aggregations:

```csharp
new SearchRequestDescriptor<Person>()
.Aggregations(aggs => aggs
.Add("my_terms", agg => agg
.Terms(terms => terms
// 8.x syntax.
.Order(new List<KeyValuePair<Field, SortOrder>>
{
new KeyValuePair<Field, SortOrder>("_key", SortOrder.Desc)
})
// 9.0 fluent syntax.
.Order(x => x
.Add(x => x.Age, SortOrder.Asc)
.Add("_key", SortOrder.Desc)
)
// 9.0 fluent add syntax (valid for all dictionary-like values).
.AddOrder("_key", SortOrder.Desc)
)
)
);
```

#### 9. Safer Object Creation

In version 9.0, users are better guided to correctly initialize objects and thus prevent invalid requests.

For this purpose, at least one constructor is now created that enforces the initialization of all required properties. Existing parameterless constructors or constructor variants that allow the creation of incomplete objects are preserved for backwards compatibility reasons, but are marked as obsolete.

For NET7+ TFMs, required properties are marked with the `required` keyword, and a non-deprecated parameterless constructor is unconditionally generated.

:::{note}

Please note that the use of descriptors still provides the chance to create incomplete objects/requests, as descriptors do not enforce the initialization of all required properties for usability reasons.

:::

#### 10. Serialization

Serialization in version 9.0 has been completely overhauled, with a primary focus on robustness and performance. Additionally, initial milestones have been set for future support of native AOT.

In 9.0, round-trip serialization is now supported for all types (limited to all JSON serializable types).

```csharp
var request = new SearchRequest{ /* ... */ };

var json = client.ElasticsearchClientSettings.RequestResponseSerializer.SerializeToString(
request,
SerializationFormatting.Indented
);

var searchRequestBody = client.ElasticsearchClientSettings.RequestResponseSerializer.Deserialize<SearchRequest>(json)!;
```

:::{warning}

Note that only the body is serialized for request types. Path- and query properties must be handled manually.

:::

:::{note}

It is important to use the `RequestResponseSerializer` when (de-)serializing client internal types. Direct use of `JsonSerializer` will not work.

:::
7 changes: 2 additions & 5 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
{
"sdk": {
"version": "8.0.400",
"version": "9.0.100",
"rollForward": "latestFeature",
"allowPrerelease": false
},
"version": "8.8.0-alpha.1",
"doc_current": "main",
"doc_branch": "main"
}
}

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -16,9 +16,14 @@
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Nullable>annotations</Nullable>
<PolySharpIncludeRuntimeSupportedAttributes>true</PolySharpIncludeRuntimeSupportedAttributes>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Elastic.Transport" Version="0.5.9" />
<PackageReference Include="PolySharp" Version="1.15.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="Tests" Key="$(ExposedPublicKey)" />
39 changes: 34 additions & 5 deletions src/Elastic.Clients.Elasticsearch/_Generated/Api/ApiUrlLookup.g.cs
Original file line number Diff line number Diff line change
@@ -17,6 +17,10 @@

#nullable restore

using System;
using System.Linq;
using Elastic.Clients.Elasticsearch.Serialization;

namespace Elastic.Clients.Elasticsearch.Requests;

internal static class ApiUrlLookup
@@ -63,6 +67,7 @@ internal static class ApiUrlLookup
internal static ApiUrls EsqlAsyncQuery = new ApiUrls(new[] { "_query/async" });
internal static ApiUrls EsqlAsyncQueryDelete = new ApiUrls(new[] { "_query/async/{id}" });
internal static ApiUrls EsqlAsyncQueryGet = new ApiUrls(new[] { "_query/async/{id}" });
internal static ApiUrls EsqlAsyncQueryStop = new ApiUrls(new[] { "_query/async/{id}/stop" });
internal static ApiUrls EsqlQuery = new ApiUrls(new[] { "_query" });
internal static ApiUrls FeaturesGetFeatures = new ApiUrls(new[] { "_features" });
internal static ApiUrls FeaturesResetFeatures = new ApiUrls(new[] { "_features/_reset" });
@@ -78,14 +83,16 @@ internal static class ApiUrlLookup
internal static ApiUrls IndexLifecycleManagementStart = new ApiUrls(new[] { "_ilm/start" });
internal static ApiUrls IndexLifecycleManagementStop = new ApiUrls(new[] { "_ilm/stop" });
internal static ApiUrls IndexManagementAnalyze = new ApiUrls(new[] { "_analyze", "{index}/_analyze" });
internal static ApiUrls IndexManagementCancelMigrateReindex = new ApiUrls(new[] { "_migration/reindex/{index}/_cancel" });
internal static ApiUrls IndexManagementClearCache = new ApiUrls(new[] { "_cache/clear", "{index}/_cache/clear" });
internal static ApiUrls IndexManagementClone = new ApiUrls(new[] { "{index}/_clone/{target}" });
internal static ApiUrls IndexManagementClose = new ApiUrls(new[] { "{index}/_close" });
internal static ApiUrls IndexManagementCreate = new ApiUrls(new[] { "{index}" });
internal static ApiUrls IndexManagementCreateDataStream = new ApiUrls(new[] { "_data_stream/{name}" });
internal static ApiUrls IndexManagementCreateFrom = new ApiUrls(new[] { "_create_from/{source}/{dest}" });
internal static ApiUrls IndexManagementDataStreamsStats = new ApiUrls(new[] { "_data_stream/_stats", "_data_stream/{name}/_stats" });
internal static ApiUrls IndexManagementDelete = new ApiUrls(new[] { "{index}" });
internal static ApiUrls IndexManagementDeleteAlias = new ApiUrls(new[] { "{index}/_alias/{name}", "{index}/_aliases/{name}" });
internal static ApiUrls IndexManagementDeleteAlias = new ApiUrls(new[] { "{index}/_alias/{name}" });
internal static ApiUrls IndexManagementDeleteDataLifecycle = new ApiUrls(new[] { "_data_stream/{name}/_lifecycle" });
internal static ApiUrls IndexManagementDeleteDataStream = new ApiUrls(new[] { "_data_stream/{name}" });
internal static ApiUrls IndexManagementDeleteIndexTemplate = new ApiUrls(new[] { "_index_template/{name}" });
@@ -108,13 +115,15 @@ internal static class ApiUrlLookup
internal static ApiUrls IndexManagementGetFieldMapping = new ApiUrls(new[] { "_mapping/field/{fields}", "{index}/_mapping/field/{fields}" });
internal static ApiUrls IndexManagementGetIndexTemplate = new ApiUrls(new[] { "_index_template", "_index_template/{name}" });
internal static ApiUrls IndexManagementGetMapping = new ApiUrls(new[] { "_mapping", "{index}/_mapping" });
internal static ApiUrls IndexManagementGetMigrateReindexStatus = new ApiUrls(new[] { "_migration/reindex/{index}/_status" });
internal static ApiUrls IndexManagementGetSettings = new ApiUrls(new[] { "_settings", "{index}/_settings", "{index}/_settings/{name}", "_settings/{name}" });
internal static ApiUrls IndexManagementGetTemplate = new ApiUrls(new[] { "_template", "_template/{name}" });
internal static ApiUrls IndexManagementMigrateReindex = new ApiUrls(new[] { "_migration/reindex" });
internal static ApiUrls IndexManagementMigrateToDataStream = new ApiUrls(new[] { "_data_stream/_migrate/{name}" });
internal static ApiUrls IndexManagementModifyDataStream = new ApiUrls(new[] { "_data_stream/_modify" });
internal static ApiUrls IndexManagementOpen = new ApiUrls(new[] { "{index}/_open" });
internal static ApiUrls IndexManagementPromoteDataStream = new ApiUrls(new[] { "_data_stream/_promote/{name}" });
internal static ApiUrls IndexManagementPutAlias = new ApiUrls(new[] { "{index}/_alias/{name}", "{index}/_aliases/{name}" });
internal static ApiUrls IndexManagementPutAlias = new ApiUrls(new[] { "{index}/_alias/{name}" });
internal static ApiUrls IndexManagementPutDataLifecycle = new ApiUrls(new[] { "_data_stream/{name}/_lifecycle" });
internal static ApiUrls IndexManagementPutIndexTemplate = new ApiUrls(new[] { "_index_template/{name}" });
internal static ApiUrls IndexManagementPutMapping = new ApiUrls(new[] { "{index}/_mapping" });
@@ -123,7 +132,7 @@ internal static class ApiUrlLookup
internal static ApiUrls IndexManagementRecovery = new ApiUrls(new[] { "_recovery", "{index}/_recovery" });
internal static ApiUrls IndexManagementRefresh = new ApiUrls(new[] { "_refresh", "{index}/_refresh" });
internal static ApiUrls IndexManagementReloadSearchAnalyzers = new ApiUrls(new[] { "{index}/_reload_search_analyzers" });
internal static ApiUrls IndexManagementResolveCluster = new ApiUrls(new[] { "_resolve/cluster/{name}" });
internal static ApiUrls IndexManagementResolveCluster = new ApiUrls(new[] { "_resolve/cluster", "_resolve/cluster/{name}" });
internal static ApiUrls IndexManagementResolveIndex = new ApiUrls(new[] { "_resolve/index/{name}" });
internal static ApiUrls IndexManagementRollover = new ApiUrls(new[] { "{alias}/_rollover", "{alias}/_rollover/{new_index}" });
internal static ApiUrls IndexManagementSegments = new ApiUrls(new[] { "_segments", "{index}/_segments" });
@@ -135,11 +144,31 @@ internal static class ApiUrlLookup
internal static ApiUrls IndexManagementStats = new ApiUrls(new[] { "_stats", "_stats/{metric}", "{index}/_stats", "{index}/_stats/{metric}" });
internal static ApiUrls IndexManagementUpdateAliases = new ApiUrls(new[] { "_aliases" });
internal static ApiUrls IndexManagementValidateQuery = new ApiUrls(new[] { "_validate/query", "{index}/_validate/query" });
internal static ApiUrls InferenceChatCompletionUnified = new ApiUrls(new[] { "_inference/chat_completion/{inference_id}/_stream" });
internal static ApiUrls InferenceCompletion = new ApiUrls(new[] { "_inference/completion/{inference_id}" });
internal static ApiUrls InferenceDelete = new ApiUrls(new[] { "_inference/{inference_id}", "_inference/{task_type}/{inference_id}" });
internal static ApiUrls InferenceGet = new ApiUrls(new[] { "_inference", "_inference/{inference_id}", "_inference/{task_type}/{inference_id}" });
internal static ApiUrls InferenceInference = new ApiUrls(new[] { "_inference/{inference_id}", "_inference/{task_type}/{inference_id}" });
internal static ApiUrls InferencePut = new ApiUrls(new[] { "_inference/{inference_id}", "_inference/{task_type}/{inference_id}" });
internal static ApiUrls InferenceStreamInference = new ApiUrls(new[] { "_inference/{inference_id}/_stream", "_inference/{task_type}/{inference_id}/_stream" });
internal static ApiUrls InferencePutAlibabacloud = new ApiUrls(new[] { "_inference/{task_type}/{alibabacloud_inference_id}" });
internal static ApiUrls InferencePutAmazonbedrock = new ApiUrls(new[] { "_inference/{task_type}/{amazonbedrock_inference_id}" });
internal static ApiUrls InferencePutAnthropic = new ApiUrls(new[] { "_inference/{task_type}/{anthropic_inference_id}" });
internal static ApiUrls InferencePutAzureaistudio = new ApiUrls(new[] { "_inference/{task_type}/{azureaistudio_inference_id}" });
internal static ApiUrls InferencePutAzureopenai = new ApiUrls(new[] { "_inference/{task_type}/{azureopenai_inference_id}" });
internal static ApiUrls InferencePutCohere = new ApiUrls(new[] { "_inference/{task_type}/{cohere_inference_id}" });
internal static ApiUrls InferencePutElasticsearch = new ApiUrls(new[] { "_inference/{task_type}/{elasticsearch_inference_id}" });
internal static ApiUrls InferencePutElser = new ApiUrls(new[] { "_inference/{task_type}/{elser_inference_id}" });
internal static ApiUrls InferencePutGoogleaistudio = new ApiUrls(new[] { "_inference/{task_type}/{googleaistudio_inference_id}" });
internal static ApiUrls InferencePutGooglevertexai = new ApiUrls(new[] { "_inference/{task_type}/{googlevertexai_inference_id}" });
internal static ApiUrls InferencePutHuggingFace = new ApiUrls(new[] { "_inference/{task_type}/{huggingface_inference_id}" });
internal static ApiUrls InferencePutJinaai = new ApiUrls(new[] { "_inference/{task_type}/{jinaai_inference_id}" });
internal static ApiUrls InferencePutMistral = new ApiUrls(new[] { "_inference/{task_type}/{mistral_inference_id}" });
internal static ApiUrls InferencePutOpenai = new ApiUrls(new[] { "_inference/{task_type}/{openai_inference_id}" });
internal static ApiUrls InferencePutVoyageai = new ApiUrls(new[] { "_inference/{task_type}/{voyageai_inference_id}" });
internal static ApiUrls InferencePutWatsonx = new ApiUrls(new[] { "_inference/{task_type}/{watsonx_inference_id}" });
internal static ApiUrls InferenceRerank = new ApiUrls(new[] { "_inference/rerank/{inference_id}" });
internal static ApiUrls InferenceSparseEmbedding = new ApiUrls(new[] { "_inference/sparse_embedding/{inference_id}" });
internal static ApiUrls InferenceStreamCompletion = new ApiUrls(new[] { "_inference/completion/{inference_id}/_stream" });
internal static ApiUrls InferenceTextEmbedding = new ApiUrls(new[] { "_inference/text_embedding/{inference_id}" });
internal static ApiUrls InferenceUpdate = new ApiUrls(new[] { "_inference/{inference_id}/_update", "_inference/{task_type}/{inference_id}/_update" });
internal static ApiUrls IngestDeleteGeoipDatabase = new ApiUrls(new[] { "_ingest/geoip/database/{id}" });
internal static ApiUrls IngestDeleteIpLocationDatabase = new ApiUrls(new[] { "_ingest/ip_location/database/{id}" });
Original file line number Diff line number Diff line change
@@ -17,60 +17,116 @@

#nullable restore

using Elastic.Clients.Elasticsearch.Fluent;
using Elastic.Clients.Elasticsearch.Requests;
using Elastic.Clients.Elasticsearch.Serialization;
using Elastic.Transport;
using Elastic.Transport.Extensions;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Linq;
using Elastic.Clients.Elasticsearch.Serialization;

namespace Elastic.Clients.Elasticsearch.AsyncSearch;

public sealed partial class AsyncSearchStatusRequestParameters : RequestParameters
public sealed partial class AsyncSearchStatusRequestParameters : Elastic.Transport.RequestParameters
{
/// <summary>
/// <para>
/// Specifies how long the async search needs to be available.
/// The length of time that the async search needs to be available.
/// Ongoing async searches and any saved search results are deleted after this period.
/// </para>
/// </summary>
public Elastic.Clients.Elasticsearch.Duration? KeepAlive { get => Q<Elastic.Clients.Elasticsearch.Duration?>("keep_alive"); set => Q("keep_alive", value); }
}

internal sealed partial class AsyncSearchStatusRequestConverter : System.Text.Json.Serialization.JsonConverter<Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequest>
{
public override Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequest Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options)
{
reader.ValidateToken(System.Text.Json.JsonTokenType.StartObject);
while (reader.Read() && reader.TokenType is System.Text.Json.JsonTokenType.PropertyName)
{
if (options.UnmappedMemberHandling is System.Text.Json.Serialization.JsonUnmappedMemberHandling.Skip)
{
reader.Skip();
continue;
}

throw new System.Text.Json.JsonException($"Unknown JSON property '{reader.GetString()}' for type '{typeToConvert.Name}'.");
}

reader.ValidateToken(System.Text.Json.JsonTokenType.EndObject);
return new Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequest(Elastic.Clients.Elasticsearch.Serialization.JsonConstructorSentinel.Instance)
{
};
}

public override void Write(System.Text.Json.Utf8JsonWriter writer, Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequest value, System.Text.Json.JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WriteEndObject();
}
}

/// <summary>
/// <para>
/// Get the async search status.
/// </para>
/// <para>
/// Get the status of a previously submitted async search request given its identifier, without retrieving search results.
/// If the Elasticsearch security features are enabled, use of this API is restricted to the <c>monitoring_user</c> role.
/// If the Elasticsearch security features are enabled, the access to the status of a specific async search is restricted to:
/// </para>
/// <list type="bullet">
/// <item>
/// <para>
/// The user or API key that submitted the original async search request.
/// </para>
/// </item>
/// <item>
/// <para>
/// Users that have the <c>monitor</c> cluster privilege or greater privileges.
/// </para>
/// </item>
/// </list>
/// </summary>
public sealed partial class AsyncSearchStatusRequest : PlainRequest<AsyncSearchStatusRequestParameters>
[System.Text.Json.Serialization.JsonConverter(typeof(Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequestConverter))]
public sealed partial class AsyncSearchStatusRequest : Elastic.Clients.Elasticsearch.Requests.PlainRequest<Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequestParameters>
{
[System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
public AsyncSearchStatusRequest(Elastic.Clients.Elasticsearch.Id id) : base(r => r.Required("id", id))
{
}
#if NET7_0_OR_GREATER
public AsyncSearchStatusRequest()
{
}
#endif
[System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
internal AsyncSearchStatusRequest(Elastic.Clients.Elasticsearch.Serialization.JsonConstructorSentinel sentinel)
{
_ = sentinel;
}

internal override ApiUrls ApiUrls => ApiUrlLookup.AsyncSearchStatus;
internal override Elastic.Clients.Elasticsearch.Requests.ApiUrls ApiUrls => Elastic.Clients.Elasticsearch.Requests.ApiUrlLookup.AsyncSearchStatus;

protected override HttpMethod StaticHttpMethod => HttpMethod.GET;
protected override Elastic.Transport.HttpMethod StaticHttpMethod => Elastic.Transport.HttpMethod.GET;

internal override bool SupportsBody => false;

internal override string OperationName => "async_search.status";

/// <summary>
/// <para>
/// Specifies how long the async search needs to be available.
/// A unique identifier for the async search.
/// </para>
/// </summary>
public
#if NET7_0_OR_GREATER
required
#endif
Elastic.Clients.Elasticsearch.Id Id { get => P<Elastic.Clients.Elasticsearch.Id>("id"); set => PR("id", value); }

/// <summary>
/// <para>
/// The length of time that the async search needs to be available.
/// Ongoing async searches and any saved search results are deleted after this period.
/// </para>
/// </summary>
[JsonIgnore]
public Elastic.Clients.Elasticsearch.Duration? KeepAlive { get => Q<Elastic.Clients.Elasticsearch.Duration?>("keep_alive"); set => Q("keep_alive", value); }
}

@@ -80,72 +136,115 @@ public AsyncSearchStatusRequest(Elastic.Clients.Elasticsearch.Id id) : base(r =>
/// </para>
/// <para>
/// Get the status of a previously submitted async search request given its identifier, without retrieving search results.
/// If the Elasticsearch security features are enabled, use of this API is restricted to the <c>monitoring_user</c> role.
/// If the Elasticsearch security features are enabled, the access to the status of a specific async search is restricted to:
/// </para>
/// <list type="bullet">
/// <item>
/// <para>
/// The user or API key that submitted the original async search request.
/// </para>
/// </item>
/// <item>
/// <para>
/// Users that have the <c>monitor</c> cluster privilege or greater privileges.
/// </para>
/// </item>
/// </list>
/// </summary>
public sealed partial class AsyncSearchStatusRequestDescriptor<TDocument> : RequestDescriptor<AsyncSearchStatusRequestDescriptor<TDocument>, AsyncSearchStatusRequestParameters>
public readonly partial struct AsyncSearchStatusRequestDescriptor
{
internal AsyncSearchStatusRequestDescriptor(Action<AsyncSearchStatusRequestDescriptor<TDocument>> configure) => configure.Invoke(this);
internal Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequest Instance { get; init; }

public AsyncSearchStatusRequestDescriptor(Elastic.Clients.Elasticsearch.Id id) : base(r => r.Required("id", id))
[System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
public AsyncSearchStatusRequestDescriptor(Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequest instance)
{
Instance = instance;
}

internal override ApiUrls ApiUrls => ApiUrlLookup.AsyncSearchStatus;

protected override HttpMethod StaticHttpMethod => HttpMethod.GET;

internal override bool SupportsBody => false;
public AsyncSearchStatusRequestDescriptor(Elastic.Clients.Elasticsearch.Id id)
{
Instance = new Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequest(id);
}

internal override string OperationName => "async_search.status";
[System.Obsolete("The use of the parameterless constructor is not permitted for this type.")]
public AsyncSearchStatusRequestDescriptor()
{
throw new System.InvalidOperationException("The use of the parameterless constructor is not permitted for this type.");
}

public AsyncSearchStatusRequestDescriptor<TDocument> KeepAlive(Elastic.Clients.Elasticsearch.Duration? keepAlive) => Qs("keep_alive", keepAlive);
public static explicit operator Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequestDescriptor(Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequest instance) => new Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequestDescriptor(instance);
public static implicit operator Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequest(Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequestDescriptor descriptor) => descriptor.Instance;

public AsyncSearchStatusRequestDescriptor<TDocument> Id(Elastic.Clients.Elasticsearch.Id id)
/// <summary>
/// <para>
/// A unique identifier for the async search.
/// </para>
/// </summary>
public Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequestDescriptor Id(Elastic.Clients.Elasticsearch.Id value)
{
RouteValues.Required("id", id);
return Self;
Instance.Id = value;
return this;
}

protected override void Serialize(Utf8JsonWriter writer, JsonSerializerOptions options, IElasticsearchClientSettings settings)
/// <summary>
/// <para>
/// The length of time that the async search needs to be available.
/// Ongoing async searches and any saved search results are deleted after this period.
/// </para>
/// </summary>
public Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequestDescriptor KeepAlive(Elastic.Clients.Elasticsearch.Duration? value)
{
Instance.KeepAlive = value;
return this;
}
}

/// <summary>
/// <para>
/// Get the async search status.
/// </para>
/// <para>
/// Get the status of a previously submitted async search request given its identifier, without retrieving search results.
/// If the Elasticsearch security features are enabled, use of this API is restricted to the <c>monitoring_user</c> role.
/// </para>
/// </summary>
public sealed partial class AsyncSearchStatusRequestDescriptor : RequestDescriptor<AsyncSearchStatusRequestDescriptor, AsyncSearchStatusRequestParameters>
{
internal AsyncSearchStatusRequestDescriptor(Action<AsyncSearchStatusRequestDescriptor> configure) => configure.Invoke(this);

public AsyncSearchStatusRequestDescriptor(Elastic.Clients.Elasticsearch.Id id) : base(r => r.Required("id", id))
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
internal static Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequest Build(System.Action<Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequestDescriptor> action)
{
var builder = new Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequestDescriptor(new Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequest(Elastic.Clients.Elasticsearch.Serialization.JsonConstructorSentinel.Instance));
action.Invoke(builder);
return builder.Instance;
}

internal override ApiUrls ApiUrls => ApiUrlLookup.AsyncSearchStatus;
public Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequestDescriptor ErrorTrace(bool? value)
{
Instance.ErrorTrace = value;
return this;
}

protected override HttpMethod StaticHttpMethod => HttpMethod.GET;
public Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequestDescriptor FilterPath(params string[]? value)
{
Instance.FilterPath = value;
return this;
}

internal override bool SupportsBody => false;
public Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequestDescriptor Human(bool? value)
{
Instance.Human = value;
return this;
}

internal override string OperationName => "async_search.status";
public Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequestDescriptor Pretty(bool? value)
{
Instance.Pretty = value;
return this;
}

public AsyncSearchStatusRequestDescriptor KeepAlive(Elastic.Clients.Elasticsearch.Duration? keepAlive) => Qs("keep_alive", keepAlive);
public Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequestDescriptor SourceQueryString(string? value)
{
Instance.SourceQueryString = value;
return this;
}

public AsyncSearchStatusRequestDescriptor Id(Elastic.Clients.Elasticsearch.Id id)
public Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequestDescriptor RequestConfiguration(Elastic.Transport.IRequestConfiguration? value)
{
RouteValues.Required("id", id);
return Self;
Instance.RequestConfiguration = value;
return this;
}

protected override void Serialize(Utf8JsonWriter writer, JsonSerializerOptions options, IElasticsearchClientSettings settings)
public Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusRequestDescriptor RequestConfiguration(System.Func<Elastic.Transport.RequestConfigurationDescriptor, Elastic.Transport.IRequestConfiguration>? configurationSelector)
{
Instance.RequestConfiguration = configurationSelector.Invoke(Instance.RequestConfiguration is null ? new Elastic.Transport.RequestConfigurationDescriptor() : new Elastic.Transport.RequestConfigurationDescriptor(Instance.RequestConfiguration)) ?? Instance.RequestConfiguration;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -17,86 +17,244 @@

#nullable restore

using Elastic.Clients.Elasticsearch.Fluent;
using Elastic.Clients.Elasticsearch.Serialization;
using Elastic.Transport.Products.Elasticsearch;
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using System.Linq;
using Elastic.Clients.Elasticsearch.Serialization;

namespace Elastic.Clients.Elasticsearch.AsyncSearch;

public sealed partial class AsyncSearchStatusResponse : ElasticsearchResponse
internal sealed partial class AsyncSearchStatusResponseConverter : System.Text.Json.Serialization.JsonConverter<Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusResponse>
{
private static readonly System.Text.Json.JsonEncodedText PropClusters = System.Text.Json.JsonEncodedText.Encode("_clusters");
private static readonly System.Text.Json.JsonEncodedText PropCompletionStatus = System.Text.Json.JsonEncodedText.Encode("completion_status");
private static readonly System.Text.Json.JsonEncodedText PropCompletionTime = System.Text.Json.JsonEncodedText.Encode("completion_time");
private static readonly System.Text.Json.JsonEncodedText PropCompletionTimeInMillis = System.Text.Json.JsonEncodedText.Encode("completion_time_in_millis");
private static readonly System.Text.Json.JsonEncodedText PropExpirationTime = System.Text.Json.JsonEncodedText.Encode("expiration_time");
private static readonly System.Text.Json.JsonEncodedText PropExpirationTimeInMillis = System.Text.Json.JsonEncodedText.Encode("expiration_time_in_millis");
private static readonly System.Text.Json.JsonEncodedText PropId = System.Text.Json.JsonEncodedText.Encode("id");
private static readonly System.Text.Json.JsonEncodedText PropIsPartial = System.Text.Json.JsonEncodedText.Encode("is_partial");
private static readonly System.Text.Json.JsonEncodedText PropIsRunning = System.Text.Json.JsonEncodedText.Encode("is_running");
private static readonly System.Text.Json.JsonEncodedText PropShards = System.Text.Json.JsonEncodedText.Encode("_shards");
private static readonly System.Text.Json.JsonEncodedText PropStartTime = System.Text.Json.JsonEncodedText.Encode("start_time");
private static readonly System.Text.Json.JsonEncodedText PropStartTimeInMillis = System.Text.Json.JsonEncodedText.Encode("start_time_in_millis");

public override Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusResponse Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options)
{
reader.ValidateToken(System.Text.Json.JsonTokenType.StartObject);
LocalJsonValue<Elastic.Clients.Elasticsearch.ClusterStatistics?> propClusters = default;
LocalJsonValue<int?> propCompletionStatus = default;
LocalJsonValue<System.DateTimeOffset?> propCompletionTime = default;
LocalJsonValue<System.DateTimeOffset?> propCompletionTimeInMillis = default;
LocalJsonValue<System.DateTimeOffset?> propExpirationTime = default;
LocalJsonValue<System.DateTimeOffset> propExpirationTimeInMillis = default;
LocalJsonValue<string?> propId = default;
LocalJsonValue<bool> propIsPartial = default;
LocalJsonValue<bool> propIsRunning = default;
LocalJsonValue<Elastic.Clients.Elasticsearch.ShardStatistics> propShards = default;
LocalJsonValue<System.DateTimeOffset?> propStartTime = default;
LocalJsonValue<System.DateTimeOffset> propStartTimeInMillis = default;
while (reader.Read() && reader.TokenType is System.Text.Json.JsonTokenType.PropertyName)
{
if (propClusters.TryReadProperty(ref reader, options, PropClusters, null))
{
continue;
}

if (propCompletionStatus.TryReadProperty(ref reader, options, PropCompletionStatus, null))
{
continue;
}

if (propCompletionTime.TryReadProperty(ref reader, options, PropCompletionTime, static System.DateTimeOffset? (ref System.Text.Json.Utf8JsonReader r, System.Text.Json.JsonSerializerOptions o) => r.ReadValueEx<System.DateTimeOffset>(o, typeof(Elastic.Clients.Elasticsearch.Serialization.DateTimeMarker))))
{
continue;
}

if (propCompletionTimeInMillis.TryReadProperty(ref reader, options, PropCompletionTimeInMillis, static System.DateTimeOffset? (ref System.Text.Json.Utf8JsonReader r, System.Text.Json.JsonSerializerOptions o) => r.ReadValueEx<System.DateTimeOffset>(o, typeof(Elastic.Clients.Elasticsearch.Serialization.DateTimeMillisMarker))))
{
continue;
}

if (propExpirationTime.TryReadProperty(ref reader, options, PropExpirationTime, static System.DateTimeOffset? (ref System.Text.Json.Utf8JsonReader r, System.Text.Json.JsonSerializerOptions o) => r.ReadValueEx<System.DateTimeOffset>(o, typeof(Elastic.Clients.Elasticsearch.Serialization.DateTimeMarker))))
{
continue;
}

if (propExpirationTimeInMillis.TryReadProperty(ref reader, options, PropExpirationTimeInMillis, static System.DateTimeOffset (ref System.Text.Json.Utf8JsonReader r, System.Text.Json.JsonSerializerOptions o) => r.ReadValueEx<System.DateTimeOffset>(o, typeof(Elastic.Clients.Elasticsearch.Serialization.DateTimeMillisMarker))))
{
continue;
}

if (propId.TryReadProperty(ref reader, options, PropId, null))
{
continue;
}

if (propIsPartial.TryReadProperty(ref reader, options, PropIsPartial, null))
{
continue;
}

if (propIsRunning.TryReadProperty(ref reader, options, PropIsRunning, null))
{
continue;
}

if (propShards.TryReadProperty(ref reader, options, PropShards, null))
{
continue;
}

if (propStartTime.TryReadProperty(ref reader, options, PropStartTime, static System.DateTimeOffset? (ref System.Text.Json.Utf8JsonReader r, System.Text.Json.JsonSerializerOptions o) => r.ReadValueEx<System.DateTimeOffset>(o, typeof(Elastic.Clients.Elasticsearch.Serialization.DateTimeMarker))))
{
continue;
}

if (propStartTimeInMillis.TryReadProperty(ref reader, options, PropStartTimeInMillis, static System.DateTimeOffset (ref System.Text.Json.Utf8JsonReader r, System.Text.Json.JsonSerializerOptions o) => r.ReadValueEx<System.DateTimeOffset>(o, typeof(Elastic.Clients.Elasticsearch.Serialization.DateTimeMillisMarker))))
{
continue;
}

if (options.UnmappedMemberHandling is System.Text.Json.Serialization.JsonUnmappedMemberHandling.Skip)
{
reader.Skip();
continue;
}

throw new System.Text.Json.JsonException($"Unknown JSON property '{reader.GetString()}' for type '{typeToConvert.Name}'.");
}

reader.ValidateToken(System.Text.Json.JsonTokenType.EndObject);
return new Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusResponse(Elastic.Clients.Elasticsearch.Serialization.JsonConstructorSentinel.Instance)
{
Clusters = propClusters.Value,
CompletionStatus = propCompletionStatus.Value,
CompletionTime = propCompletionTime.Value,
CompletionTimeInMillis = propCompletionTimeInMillis.Value,
ExpirationTime = propExpirationTime.Value,
ExpirationTimeInMillis = propExpirationTimeInMillis.Value,
Id = propId.Value,
IsPartial = propIsPartial.Value,
IsRunning = propIsRunning.Value,
Shards = propShards.Value,
StartTime = propStartTime.Value,
StartTimeInMillis = propStartTimeInMillis.Value
};
}

public override void Write(System.Text.Json.Utf8JsonWriter writer, Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusResponse value, System.Text.Json.JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WriteProperty(options, PropClusters, value.Clusters, null, null);
writer.WriteProperty(options, PropCompletionStatus, value.CompletionStatus, null, null);
writer.WriteProperty(options, PropCompletionTime, value.CompletionTime, null, static (System.Text.Json.Utf8JsonWriter w, System.Text.Json.JsonSerializerOptions o, System.DateTimeOffset? v) => w.WriteValueEx<System.DateTimeOffset>(o, v, typeof(Elastic.Clients.Elasticsearch.Serialization.DateTimeMarker)));
writer.WriteProperty(options, PropCompletionTimeInMillis, value.CompletionTimeInMillis, null, static (System.Text.Json.Utf8JsonWriter w, System.Text.Json.JsonSerializerOptions o, System.DateTimeOffset? v) => w.WriteValueEx<System.DateTimeOffset>(o, v, typeof(Elastic.Clients.Elasticsearch.Serialization.DateTimeMillisMarker)));
writer.WriteProperty(options, PropExpirationTime, value.ExpirationTime, null, static (System.Text.Json.Utf8JsonWriter w, System.Text.Json.JsonSerializerOptions o, System.DateTimeOffset? v) => w.WriteValueEx<System.DateTimeOffset>(o, v, typeof(Elastic.Clients.Elasticsearch.Serialization.DateTimeMarker)));
writer.WriteProperty(options, PropExpirationTimeInMillis, value.ExpirationTimeInMillis, null, static (System.Text.Json.Utf8JsonWriter w, System.Text.Json.JsonSerializerOptions o, System.DateTimeOffset v) => w.WriteValueEx<System.DateTimeOffset>(o, v, typeof(Elastic.Clients.Elasticsearch.Serialization.DateTimeMillisMarker)));
writer.WriteProperty(options, PropId, value.Id, null, null);
writer.WriteProperty(options, PropIsPartial, value.IsPartial, null, null);
writer.WriteProperty(options, PropIsRunning, value.IsRunning, null, null);
writer.WriteProperty(options, PropShards, value.Shards, null, null);
writer.WriteProperty(options, PropStartTime, value.StartTime, null, static (System.Text.Json.Utf8JsonWriter w, System.Text.Json.JsonSerializerOptions o, System.DateTimeOffset? v) => w.WriteValueEx<System.DateTimeOffset>(o, v, typeof(Elastic.Clients.Elasticsearch.Serialization.DateTimeMarker)));
writer.WriteProperty(options, PropStartTimeInMillis, value.StartTimeInMillis, null, static (System.Text.Json.Utf8JsonWriter w, System.Text.Json.JsonSerializerOptions o, System.DateTimeOffset v) => w.WriteValueEx<System.DateTimeOffset>(o, v, typeof(Elastic.Clients.Elasticsearch.Serialization.DateTimeMillisMarker)));
writer.WriteEndObject();
}
}

[System.Text.Json.Serialization.JsonConverter(typeof(Elastic.Clients.Elasticsearch.AsyncSearch.AsyncSearchStatusResponseConverter))]
public sealed partial class AsyncSearchStatusResponse : Elastic.Transport.Products.Elasticsearch.ElasticsearchResponse
{
[System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
public AsyncSearchStatusResponse()
{
}

[System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
internal AsyncSearchStatusResponse(Elastic.Clients.Elasticsearch.Serialization.JsonConstructorSentinel sentinel)
{
_ = sentinel;
}

/// <summary>
/// <para>
/// Metadata about clusters involved in the cross-cluster search.
/// Not shown for local-only searches.
/// It is not shown for local-only searches.
/// </para>
/// </summary>
[JsonInclude, JsonPropertyName("_clusters")]
public Elastic.Clients.Elasticsearch.ClusterStatistics? Clusters { get; init; }
public Elastic.Clients.Elasticsearch.ClusterStatistics? Clusters { get; set; }

/// <summary>
/// <para>
/// If the async search completed, this field shows the status code of the search.
/// For example, 200 indicates that the async search was successfully completed.
/// 503 indicates that the async search was completed with an error.
/// For example, <c>200</c> indicates that the async search was successfully completed.
/// <c>503</c> indicates that the async search was completed with an error.
/// </para>
/// </summary>
[JsonInclude, JsonPropertyName("completion_status")]
public int? CompletionStatus { get; init; }
public int? CompletionStatus { get; set; }

/// <summary>
/// <para>
/// Indicates when the async search completed. Only present
/// when the search has completed.
/// Indicates when the async search completed.
/// It is present only when the search has completed.
/// </para>
/// </summary>
[JsonInclude, JsonPropertyName("completion_time")]
public DateTimeOffset? CompletionTime { get; init; }
[JsonInclude, JsonPropertyName("completion_time_in_millis")]
public long? CompletionTimeInMillis { get; init; }
public System.DateTimeOffset? CompletionTime { get; set; }
public System.DateTimeOffset? CompletionTimeInMillis { get; set; }

/// <summary>
/// <para>
/// Indicates when the async search will expire.
/// </para>
/// </summary>
[JsonInclude, JsonPropertyName("expiration_time")]
public DateTimeOffset? ExpirationTime { get; init; }
[JsonInclude, JsonPropertyName("expiration_time_in_millis")]
public long ExpirationTimeInMillis { get; init; }
[JsonInclude, JsonPropertyName("id")]
public string? Id { get; init; }
public System.DateTimeOffset? ExpirationTime { get; set; }
public
#if NET7_0_OR_GREATER
required
#endif
System.DateTimeOffset ExpirationTimeInMillis { get; set; }
public string? Id { get; set; }

/// <summary>
/// <para>
/// When the query is no longer running, this property indicates whether the search failed or was successfully completed on all shards.
/// While the query is running, <c>is_partial</c> is always set to <c>true</c>.
/// </para>
/// </summary>
[JsonInclude, JsonPropertyName("is_partial")]
public bool IsPartial { get; init; }
public
#if NET7_0_OR_GREATER
required
#endif
bool IsPartial { get; set; }

/// <summary>
/// <para>
/// Indicates whether the search is still running or has completed.
/// NOTE: If the search failed after some shards returned their results or the node that is coordinating the async search dies, results may be partial even though <c>is_running</c> is <c>false</c>.
/// </para>
/// <para>
/// info
/// If the search failed after some shards returned their results or the node that is coordinating the async search dies, results may be partial even though <c>is_running</c> is <c>false</c>.
/// </para>
/// </summary>
[JsonInclude, JsonPropertyName("is_running")]
public bool IsRunning { get; init; }
public
#if NET7_0_OR_GREATER
required
#endif
bool IsRunning { get; set; }

/// <summary>
/// <para>
/// Indicates how many shards have run the query so far.
/// The number of shards that have run the query so far.
/// </para>
/// </summary>
[JsonInclude, JsonPropertyName("_shards")]
public Elastic.Clients.Elasticsearch.ShardStatistics Shards { get; init; }
[JsonInclude, JsonPropertyName("start_time")]
public DateTimeOffset? StartTime { get; init; }
[JsonInclude, JsonPropertyName("start_time_in_millis")]
public long StartTimeInMillis { get; init; }
public
#if NET7_0_OR_GREATER
required
#endif
Elastic.Clients.Elasticsearch.ShardStatistics Shards { get; set; }
public System.DateTimeOffset? StartTime { get; set; }
public
#if NET7_0_OR_GREATER
required
#endif
System.DateTimeOffset StartTimeInMillis { get; set; }
}
Original file line number Diff line number Diff line change
@@ -17,21 +17,43 @@

#nullable restore

using Elastic.Clients.Elasticsearch.Fluent;
using Elastic.Clients.Elasticsearch.Requests;
using Elastic.Clients.Elasticsearch.Serialization;
using Elastic.Transport;
using Elastic.Transport.Extensions;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Linq;
using Elastic.Clients.Elasticsearch.Serialization;

namespace Elastic.Clients.Elasticsearch.AsyncSearch;

public sealed partial class DeleteAsyncSearchRequestParameters : RequestParameters
public sealed partial class DeleteAsyncSearchRequestParameters : Elastic.Transport.RequestParameters
{
}

internal sealed partial class DeleteAsyncSearchRequestConverter : System.Text.Json.Serialization.JsonConverter<Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequest>
{
public override Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequest Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options)
{
reader.ValidateToken(System.Text.Json.JsonTokenType.StartObject);
while (reader.Read() && reader.TokenType is System.Text.Json.JsonTokenType.PropertyName)
{
if (options.UnmappedMemberHandling is System.Text.Json.Serialization.JsonUnmappedMemberHandling.Skip)
{
reader.Skip();
continue;
}

throw new System.Text.Json.JsonException($"Unknown JSON property '{reader.GetString()}' for type '{typeToConvert.Name}'.");
}

reader.ValidateToken(System.Text.Json.JsonTokenType.EndObject);
return new Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequest(Elastic.Clients.Elasticsearch.Serialization.JsonConstructorSentinel.Instance)
{
};
}

public override void Write(System.Text.Json.Utf8JsonWriter writer, Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequest value, System.Text.Json.JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WriteEndObject();
}
}

/// <summary>
@@ -44,19 +66,42 @@ public sealed partial class DeleteAsyncSearchRequestParameters : RequestParamete
/// If the Elasticsearch security features are enabled, the deletion of a specific async search is restricted to: the authenticated user that submitted the original search request; users that have the <c>cancel_task</c> cluster privilege.
/// </para>
/// </summary>
public sealed partial class DeleteAsyncSearchRequest : PlainRequest<DeleteAsyncSearchRequestParameters>
[System.Text.Json.Serialization.JsonConverter(typeof(Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequestConverter))]
public sealed partial class DeleteAsyncSearchRequest : Elastic.Clients.Elasticsearch.Requests.PlainRequest<Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequestParameters>
{
[System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
public DeleteAsyncSearchRequest(Elastic.Clients.Elasticsearch.Id id) : base(r => r.Required("id", id))
{
}
#if NET7_0_OR_GREATER
public DeleteAsyncSearchRequest()
{
}
#endif
[System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
internal DeleteAsyncSearchRequest(Elastic.Clients.Elasticsearch.Serialization.JsonConstructorSentinel sentinel)
{
_ = sentinel;
}

internal override ApiUrls ApiUrls => ApiUrlLookup.AsyncSearchDelete;
internal override Elastic.Clients.Elasticsearch.Requests.ApiUrls ApiUrls => Elastic.Clients.Elasticsearch.Requests.ApiUrlLookup.AsyncSearchDelete;

protected override HttpMethod StaticHttpMethod => HttpMethod.DELETE;
protected override Elastic.Transport.HttpMethod StaticHttpMethod => Elastic.Transport.HttpMethod.DELETE;

internal override bool SupportsBody => false;

internal override string OperationName => "async_search.delete";

/// <summary>
/// <para>
/// A unique identifier for the async search.
/// </para>
/// </summary>
public
#if NET7_0_OR_GREATER
required
#endif
Elastic.Clients.Elasticsearch.Id Id { get => P<Elastic.Clients.Elasticsearch.Id>("id"); set => PR("id", value); }
}

/// <summary>
@@ -69,66 +114,88 @@ public DeleteAsyncSearchRequest(Elastic.Clients.Elasticsearch.Id id) : base(r =>
/// If the Elasticsearch security features are enabled, the deletion of a specific async search is restricted to: the authenticated user that submitted the original search request; users that have the <c>cancel_task</c> cluster privilege.
/// </para>
/// </summary>
public sealed partial class DeleteAsyncSearchRequestDescriptor<TDocument> : RequestDescriptor<DeleteAsyncSearchRequestDescriptor<TDocument>, DeleteAsyncSearchRequestParameters>
public readonly partial struct DeleteAsyncSearchRequestDescriptor
{
internal DeleteAsyncSearchRequestDescriptor(Action<DeleteAsyncSearchRequestDescriptor<TDocument>> configure) => configure.Invoke(this);
internal Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequest Instance { get; init; }

public DeleteAsyncSearchRequestDescriptor(Elastic.Clients.Elasticsearch.Id id) : base(r => r.Required("id", id))
[System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
public DeleteAsyncSearchRequestDescriptor(Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequest instance)
{
Instance = instance;
}

internal override ApiUrls ApiUrls => ApiUrlLookup.AsyncSearchDelete;

protected override HttpMethod StaticHttpMethod => HttpMethod.DELETE;
public DeleteAsyncSearchRequestDescriptor(Elastic.Clients.Elasticsearch.Id id)
{
Instance = new Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequest(id);
}

internal override bool SupportsBody => false;
[System.Obsolete("The use of the parameterless constructor is not permitted for this type.")]
public DeleteAsyncSearchRequestDescriptor()
{
throw new System.InvalidOperationException("The use of the parameterless constructor is not permitted for this type.");
}

internal override string OperationName => "async_search.delete";
public static explicit operator Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequestDescriptor(Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequest instance) => new Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequestDescriptor(instance);
public static implicit operator Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequest(Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequestDescriptor descriptor) => descriptor.Instance;

public DeleteAsyncSearchRequestDescriptor<TDocument> Id(Elastic.Clients.Elasticsearch.Id id)
/// <summary>
/// <para>
/// A unique identifier for the async search.
/// </para>
/// </summary>
public Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequestDescriptor Id(Elastic.Clients.Elasticsearch.Id value)
{
RouteValues.Required("id", id);
return Self;
Instance.Id = value;
return this;
}

protected override void Serialize(Utf8JsonWriter writer, JsonSerializerOptions options, IElasticsearchClientSettings settings)
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
internal static Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequest Build(System.Action<Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequestDescriptor> action)
{
var builder = new Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequestDescriptor(new Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequest(Elastic.Clients.Elasticsearch.Serialization.JsonConstructorSentinel.Instance));
action.Invoke(builder);
return builder.Instance;
}
}

/// <summary>
/// <para>
/// Delete an async search.
/// </para>
/// <para>
/// If the asynchronous search is still running, it is cancelled.
/// Otherwise, the saved search results are deleted.
/// If the Elasticsearch security features are enabled, the deletion of a specific async search is restricted to: the authenticated user that submitted the original search request; users that have the <c>cancel_task</c> cluster privilege.
/// </para>
/// </summary>
public sealed partial class DeleteAsyncSearchRequestDescriptor : RequestDescriptor<DeleteAsyncSearchRequestDescriptor, DeleteAsyncSearchRequestParameters>
{
internal DeleteAsyncSearchRequestDescriptor(Action<DeleteAsyncSearchRequestDescriptor> configure) => configure.Invoke(this);

public DeleteAsyncSearchRequestDescriptor(Elastic.Clients.Elasticsearch.Id id) : base(r => r.Required("id", id))
public Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequestDescriptor ErrorTrace(bool? value)
{
Instance.ErrorTrace = value;
return this;
}

internal override ApiUrls ApiUrls => ApiUrlLookup.AsyncSearchDelete;
public Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequestDescriptor FilterPath(params string[]? value)
{
Instance.FilterPath = value;
return this;
}

protected override HttpMethod StaticHttpMethod => HttpMethod.DELETE;
public Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequestDescriptor Human(bool? value)
{
Instance.Human = value;
return this;
}

internal override bool SupportsBody => false;
public Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequestDescriptor Pretty(bool? value)
{
Instance.Pretty = value;
return this;
}

internal override string OperationName => "async_search.delete";
public Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequestDescriptor SourceQueryString(string? value)
{
Instance.SourceQueryString = value;
return this;
}

public DeleteAsyncSearchRequestDescriptor Id(Elastic.Clients.Elasticsearch.Id id)
public Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequestDescriptor RequestConfiguration(Elastic.Transport.IRequestConfiguration? value)
{
RouteValues.Required("id", id);
return Self;
Instance.RequestConfiguration = value;
return this;
}

protected override void Serialize(Utf8JsonWriter writer, JsonSerializerOptions options, IElasticsearchClientSettings settings)
public Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchRequestDescriptor RequestConfiguration(System.Func<Elastic.Transport.RequestConfigurationDescriptor, Elastic.Transport.IRequestConfiguration>? configurationSelector)
{
Instance.RequestConfiguration = configurationSelector.Invoke(Instance.RequestConfiguration is null ? new Elastic.Transport.RequestConfigurationDescriptor() : new Elastic.Transport.RequestConfigurationDescriptor(Instance.RequestConfiguration)) ?? Instance.RequestConfiguration;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -17,22 +17,73 @@

#nullable restore

using Elastic.Clients.Elasticsearch.Fluent;
using Elastic.Clients.Elasticsearch.Serialization;
using Elastic.Transport.Products.Elasticsearch;
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using System.Linq;
using Elastic.Clients.Elasticsearch.Serialization;

namespace Elastic.Clients.Elasticsearch.AsyncSearch;

public sealed partial class DeleteAsyncSearchResponse : ElasticsearchResponse
internal sealed partial class DeleteAsyncSearchResponseConverter : System.Text.Json.Serialization.JsonConverter<Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchResponse>
{
private static readonly System.Text.Json.JsonEncodedText PropAcknowledged = System.Text.Json.JsonEncodedText.Encode("acknowledged");

public override Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchResponse Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options)
{
reader.ValidateToken(System.Text.Json.JsonTokenType.StartObject);
LocalJsonValue<bool> propAcknowledged = default;
while (reader.Read() && reader.TokenType is System.Text.Json.JsonTokenType.PropertyName)
{
if (propAcknowledged.TryReadProperty(ref reader, options, PropAcknowledged, null))
{
continue;
}

if (options.UnmappedMemberHandling is System.Text.Json.Serialization.JsonUnmappedMemberHandling.Skip)
{
reader.Skip();
continue;
}

throw new System.Text.Json.JsonException($"Unknown JSON property '{reader.GetString()}' for type '{typeToConvert.Name}'.");
}

reader.ValidateToken(System.Text.Json.JsonTokenType.EndObject);
return new Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchResponse(Elastic.Clients.Elasticsearch.Serialization.JsonConstructorSentinel.Instance)
{
Acknowledged = propAcknowledged.Value
};
}

public override void Write(System.Text.Json.Utf8JsonWriter writer, Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchResponse value, System.Text.Json.JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WriteProperty(options, PropAcknowledged, value.Acknowledged, null, null);
writer.WriteEndObject();
}
}

[System.Text.Json.Serialization.JsonConverter(typeof(Elastic.Clients.Elasticsearch.AsyncSearch.DeleteAsyncSearchResponseConverter))]
public sealed partial class DeleteAsyncSearchResponse : Elastic.Transport.Products.Elasticsearch.ElasticsearchResponse
{
[System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
public DeleteAsyncSearchResponse()
{
}

[System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
internal DeleteAsyncSearchResponse(Elastic.Clients.Elasticsearch.Serialization.JsonConstructorSentinel sentinel)
{
_ = sentinel;
}

/// <summary>
/// <para>
/// For a successful response, this value is always true. On failure, an exception is returned instead.
/// </para>
/// </summary>
[JsonInclude, JsonPropertyName("acknowledged")]
public bool Acknowledged { get; init; }
public
#if NET7_0_OR_GREATER
required
#endif
bool Acknowledged { get; set; }
}
Loading