diff --git a/src/Elasticsearch.Net/Api/RequestParameters/RequestParameters.AsyncSearch.cs b/src/Elasticsearch.Net/Api/RequestParameters/RequestParameters.AsyncSearch.cs index 8a0f67c6d6c..f1a944c0119 100644 --- a/src/Elasticsearch.Net/Api/RequestParameters/RequestParameters.AsyncSearch.cs +++ b/src/Elasticsearch.Net/Api/RequestParameters/RequestParameters.AsyncSearch.cs @@ -59,7 +59,7 @@ public TimeSpan WaitForCompletionTimeout } ///Request options for Status https://www.elastic.co/guide/en/elasticsearch/reference/current/async-search.html - public class StatusRequestParameters : RequestParameters + public class AsyncSearchStatusRequestParameters : RequestParameters { public override HttpMethod DefaultHttpMethod => HttpMethod.GET; public override bool SupportsBody => false; diff --git a/src/Elasticsearch.Net/ElasticLowLevelClient.AsyncSearch.cs b/src/Elasticsearch.Net/ElasticLowLevelClient.AsyncSearch.cs index c46afb85555..36842c6685a 100644 --- a/src/Elasticsearch.Net/ElasticLowLevelClient.AsyncSearch.cs +++ b/src/Elasticsearch.Net/ElasticLowLevelClient.AsyncSearch.cs @@ -68,13 +68,13 @@ public Task GetAsync(string id, AsyncSearchGetRequestParam ///GET on /_async_search/status/{id} https://www.elastic.co/guide/en/elasticsearch/reference/current/async-search.html ///The async search ID ///Request specific configuration such as querystring parameters & request specific connection settings. - public TResponse Status(string id, StatusRequestParameters requestParameters = null) + public TResponse Status(string id, AsyncSearchStatusRequestParameters requestParameters = null) where TResponse : class, IElasticsearchResponse, new() => DoRequest(GET, Url($"_async_search/status/{id:id}"), null, RequestParams(requestParameters)); ///GET on /_async_search/status/{id} https://www.elastic.co/guide/en/elasticsearch/reference/current/async-search.html ///The async search ID ///Request specific configuration such as querystring parameters & request specific connection settings. [MapsApi("async_search.status", "id")] - public Task StatusAsync(string id, StatusRequestParameters requestParameters = null, CancellationToken ctx = default) + public Task StatusAsync(string id, AsyncSearchStatusRequestParameters requestParameters = null, CancellationToken ctx = default) where TResponse : class, IElasticsearchResponse, new() => DoRequestAsync(GET, Url($"_async_search/status/{id:id}"), ctx, null, RequestParams(requestParameters)); ///POST on /_async_search https://www.elastic.co/guide/en/elasticsearch/reference/current/async-search.html ///The search definition using the Query DSL diff --git a/src/Nest/Descriptors.AsyncSearch.cs b/src/Nest/Descriptors.AsyncSearch.cs index a007d79d069..9ef63ee0156 100644 --- a/src/Nest/Descriptors.AsyncSearch.cs +++ b/src/Nest/Descriptors.AsyncSearch.cs @@ -78,6 +78,27 @@ protected AsyncSearchGetDescriptor(): base() public AsyncSearchGetDescriptor WaitForCompletionTimeout(Time waitforcompletiontimeout) => Qs("wait_for_completion_timeout", waitforcompletiontimeout); } + ///Descriptor for Status https://www.elastic.co/guide/en/elasticsearch/reference/current/async-search.html + public partial class AsyncSearchStatusDescriptor : RequestDescriptorBase, IAsyncSearchStatusRequest + { + internal override ApiUrls ApiUrls => ApiUrlsLookups.AsyncSearchStatus; + ////_async_search/status/{id} + ///this parameter is required + public AsyncSearchStatusDescriptor(Id id): base(r => r.Required("id", id)) + { + } + + ///Used for serialization purposes, making sure we have a parameterless constructor + [SerializationConstructor] + protected AsyncSearchStatusDescriptor(): base() + { + } + + // values part of the url path + Id IAsyncSearchStatusRequest.Id => Self.RouteValues.Get("id"); + // Request parameters + } + ///Descriptor for Submit https://www.elastic.co/guide/en/elasticsearch/reference/current/async-search.html public partial class AsyncSearchSubmitDescriptor : RequestDescriptorBase, AsyncSearchSubmitRequestParameters, IAsyncSearchSubmitRequest>, IAsyncSearchSubmitRequest { diff --git a/src/Nest/ElasticClient.AsyncSearch.cs b/src/Nest/ElasticClient.AsyncSearch.cs index a2312226f5d..38532681029 100644 --- a/src/Nest/ElasticClient.AsyncSearch.cs +++ b/src/Nest/ElasticClient.AsyncSearch.cs @@ -89,6 +89,30 @@ public AsyncSearchGetResponse Get(IAsyncSearchGetRequest r public Task> GetAsync(IAsyncSearchGetRequest request, CancellationToken ct = default) where TDocument : class => DoRequestAsync>(request, request.RequestParameters, ct); /// + /// GET request to the async_search.status API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/async-search.html + /// + public AsyncSearchStatusResponse Status(Id id, Func selector = null) => Status(selector.InvokeOrDefault(new AsyncSearchStatusDescriptor(id: id))); + /// + /// GET request to the async_search.status API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/async-search.html + /// + public Task StatusAsync(Id id, Func selector = null, CancellationToken ct = default) => StatusAsync(selector.InvokeOrDefault(new AsyncSearchStatusDescriptor(id: id)), ct); + /// + /// GET request to the async_search.status API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/async-search.html + /// + public AsyncSearchStatusResponse Status(IAsyncSearchStatusRequest request) => DoRequest(request, request.RequestParameters); + /// + /// GET request to the async_search.status API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/async-search.html + /// + public Task StatusAsync(IAsyncSearchStatusRequest request, CancellationToken ct = default) => DoRequestAsync(request, request.RequestParameters, ct); + /// /// POST request to the async_search.submit API, read more about this API online: /// /// https://www.elastic.co/guide/en/elasticsearch/reference/current/async-search.html diff --git a/src/Nest/Requests.AsyncSearch.cs b/src/Nest/Requests.AsyncSearch.cs index 24a91bb7e9c..de1e149ac5c 100644 --- a/src/Nest/Requests.AsyncSearch.cs +++ b/src/Nest/Requests.AsyncSearch.cs @@ -117,6 +117,39 @@ public Time WaitForCompletionTimeout } } + [InterfaceDataContract] + public partial interface IAsyncSearchStatusRequest : IRequest + { + [IgnoreDataMember] + Id Id + { + get; + } + } + + ///Request for Status https://www.elastic.co/guide/en/elasticsearch/reference/current/async-search.html + public partial class AsyncSearchStatusRequest : PlainRequestBase, IAsyncSearchStatusRequest + { + protected IAsyncSearchStatusRequest Self => this; + internal override ApiUrls ApiUrls => ApiUrlsLookups.AsyncSearchStatus; + ////_async_search/status/{id} + ///this parameter is required + public AsyncSearchStatusRequest(Id id): base(r => r.Required("id", id)) + { + } + + ///Used for serialization purposes, making sure we have a parameterless constructor + [SerializationConstructor] + protected AsyncSearchStatusRequest(): base() + { + } + + // values part of the url path + [IgnoreDataMember] + Id IAsyncSearchStatusRequest.Id => Self.RouteValues.Get("id"); + // Request parameters + } + [InterfaceDataContract] public partial interface IAsyncSearchSubmitRequest : IRequest { diff --git a/src/Nest/XPack/AsyncSearch/AsyncSearch.cs b/src/Nest/XPack/AsyncSearch/AsyncSearch.cs index 3d7fc79cd5e..f5eee1af58e 100644 --- a/src/Nest/XPack/AsyncSearch/AsyncSearch.cs +++ b/src/Nest/XPack/AsyncSearch/AsyncSearch.cs @@ -1,3 +1,7 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; diff --git a/src/Nest/XPack/AsyncSearch/AsyncSearchResponseBase.cs b/src/Nest/XPack/AsyncSearch/AsyncSearchResponseBase.cs index 0a51af039ff..12f491cf8c4 100644 --- a/src/Nest/XPack/AsyncSearch/AsyncSearchResponseBase.cs +++ b/src/Nest/XPack/AsyncSearch/AsyncSearchResponseBase.cs @@ -1,3 +1,7 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + using System; using System.Runtime.Serialization; using Elasticsearch.Net.Utf8Json; diff --git a/src/Nest/XPack/AsyncSearch/Delete/AsyncSearchDeleteRequest.cs b/src/Nest/XPack/AsyncSearch/Delete/AsyncSearchDeleteRequest.cs index b1da28890d7..7a69eff7570 100644 --- a/src/Nest/XPack/AsyncSearch/Delete/AsyncSearchDeleteRequest.cs +++ b/src/Nest/XPack/AsyncSearch/Delete/AsyncSearchDeleteRequest.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information namespace Nest { diff --git a/src/Nest/XPack/AsyncSearch/Delete/AsyncSearchDeleteResponse.cs b/src/Nest/XPack/AsyncSearch/Delete/AsyncSearchDeleteResponse.cs index 60b912213b8..5fb374f9c4d 100644 --- a/src/Nest/XPack/AsyncSearch/Delete/AsyncSearchDeleteResponse.cs +++ b/src/Nest/XPack/AsyncSearch/Delete/AsyncSearchDeleteResponse.cs @@ -1,3 +1,7 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + namespace Nest { public class AsyncSearchDeleteResponse : AcknowledgedResponseBase { } diff --git a/src/Nest/XPack/AsyncSearch/Get/AsyncSearchGetRequest.cs b/src/Nest/XPack/AsyncSearch/Get/AsyncSearchGetRequest.cs index debf7e93852..e545d0ab65a 100644 --- a/src/Nest/XPack/AsyncSearch/Get/AsyncSearchGetRequest.cs +++ b/src/Nest/XPack/AsyncSearch/Get/AsyncSearchGetRequest.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information namespace Nest { diff --git a/src/Nest/XPack/AsyncSearch/Get/AsyncSearchGetResponse.cs b/src/Nest/XPack/AsyncSearch/Get/AsyncSearchGetResponse.cs index edbf32e12dd..7b24dfb1425 100644 --- a/src/Nest/XPack/AsyncSearch/Get/AsyncSearchGetResponse.cs +++ b/src/Nest/XPack/AsyncSearch/Get/AsyncSearchGetResponse.cs @@ -1,3 +1,7 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + namespace Nest { public class AsyncSearchGetResponse : AsyncSearchResponseBase where TDocument : class { } diff --git a/src/Nest/XPack/AsyncSearch/Status/AsyncSearchStatusRequest.cs b/src/Nest/XPack/AsyncSearch/Status/AsyncSearchStatusRequest.cs new file mode 100644 index 00000000000..36aedd28d70 --- /dev/null +++ b/src/Nest/XPack/AsyncSearch/Status/AsyncSearchStatusRequest.cs @@ -0,0 +1,20 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + +namespace Nest +{ + [MapsApi("async_search.status.json")] + [ReadAs(typeof(AsyncSearchStatusRequest))] + public partial interface IAsyncSearchStatusRequest { } + + /// + public partial class AsyncSearchStatusRequest + { + } + + /// + public partial class AsyncSearchStatusDescriptor + { + } +} diff --git a/src/Nest/XPack/AsyncSearch/Status/AsyncSearchStatusResponse.cs b/src/Nest/XPack/AsyncSearch/Status/AsyncSearchStatusResponse.cs new file mode 100644 index 00000000000..c72e28361e8 --- /dev/null +++ b/src/Nest/XPack/AsyncSearch/Status/AsyncSearchStatusResponse.cs @@ -0,0 +1,39 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + +using System; +using System.Runtime.Serialization; + +namespace Nest +{ + public class AsyncSearchStatusResponse : ResponseBase + { + [DataMember(Name = "_shards")] + public ShardStatistics Shards { get; internal set; } + + [DataMember(Name = "completion_status")] + public int? CompletionStatus { get; internal set; } + + [DataMember(Name = "id")] + public string Id { get; internal set; } + + [DataMember(Name = "is_partial")] + public bool IsPartial { get; internal set; } + + [DataMember(Name = "start_time_in_millis")] + public long StartTimeInMilliseconds { get; internal set; } + + [IgnoreDataMember] + public DateTimeOffset StartTime => DateTimeUtil.UnixEpoch.AddMilliseconds(StartTimeInMilliseconds); + + [DataMember(Name = "is_running")] + public bool IsRunning { get; internal set; } + + [DataMember(Name = "expiration_time_in_millis")] + public long ExpirationTimeInMilliseconds { get; internal set; } + + [IgnoreDataMember] + public DateTimeOffset ExpirationTime => DateTimeUtil.UnixEpoch.AddMilliseconds(ExpirationTimeInMilliseconds); + } +} diff --git a/src/Nest/XPack/AsyncSearch/Submit/AsyncSearchSubmitRequest.cs b/src/Nest/XPack/AsyncSearch/Submit/AsyncSearchSubmitRequest.cs index 1a7e62a6bcd..4c8673fc042 100644 --- a/src/Nest/XPack/AsyncSearch/Submit/AsyncSearchSubmitRequest.cs +++ b/src/Nest/XPack/AsyncSearch/Submit/AsyncSearchSubmitRequest.cs @@ -1,3 +1,7 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + using System; using System.Collections.Generic; using System.Runtime.Serialization; diff --git a/src/Nest/XPack/AsyncSearch/Submit/AsyncSearchSubmitResponse.cs b/src/Nest/XPack/AsyncSearch/Submit/AsyncSearchSubmitResponse.cs index 22a3467591a..0b4fa349524 100644 --- a/src/Nest/XPack/AsyncSearch/Submit/AsyncSearchSubmitResponse.cs +++ b/src/Nest/XPack/AsyncSearch/Submit/AsyncSearchSubmitResponse.cs @@ -1,3 +1,7 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + namespace Nest { public class AsyncSearchSubmitResponse : AsyncSearchResponseBase diff --git a/src/Nest/_Generated/ApiUrlsLookup.generated.cs b/src/Nest/_Generated/ApiUrlsLookup.generated.cs index ef53bce3a78..775a4704750 100644 --- a/src/Nest/_Generated/ApiUrlsLookup.generated.cs +++ b/src/Nest/_Generated/ApiUrlsLookup.generated.cs @@ -20,6 +20,7 @@ internal static class ApiUrlsLookups { internal static ApiUrls AsyncSearchDelete = new ApiUrls(new[]{"_async_search/{id}"}); internal static ApiUrls AsyncSearchGet = new ApiUrls(new[]{"_async_search/{id}"}); + internal static ApiUrls AsyncSearchStatus = new ApiUrls(new[]{"_async_search/status/{id}"}); internal static ApiUrls AsyncSearchSubmit = new ApiUrls(new[]{"_async_search", "{index}/_async_search"}); internal static ApiUrls NoNamespaceBulk = new ApiUrls(new[]{"_bulk", "{index}/_bulk"}); internal static ApiUrls CatAliases = new ApiUrls(new[]{"_cat/aliases", "_cat/aliases/{name}"}); diff --git a/tests/Tests/XPack/AsyncSearch/AsyncSearchApiTests.cs b/tests/Tests/XPack/AsyncSearch/AsyncSearchApiTests.cs index 82deef4e41f..c90b213a833 100644 --- a/tests/Tests/XPack/AsyncSearch/AsyncSearchApiTests.cs +++ b/tests/Tests/XPack/AsyncSearch/AsyncSearchApiTests.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading.Tasks; using Elastic.Elasticsearch.Xunit.XunitPlumbing; @@ -17,6 +16,7 @@ namespace Tests.XPack.AsyncSearch public class AsyncSearchApiTests : CoordinatedIntegrationTestBase { private const string SubmitStep = nameof(SubmitStep); + private const string StatusStep = nameof(StatusStep); private const string GetStep = nameof(GetStep); private const string DeleteStep = nameof(DeleteStep); @@ -71,6 +71,17 @@ public AsyncSearchApiTests(ReadOnlyCluster cluster, EndpointUsage usage) : base( onResponse: (r, values) => values.ExtendedValue("id", r.Id) ) }, + {StatusStep, ">=7.11.0", u => + u.Calls( + v => new AsyncSearchStatusRequest(v), + (v, d) => d, + (v, c, f) => c.AsyncSearch.Status(v, f), + (v, c, f) => c.AsyncSearch.StatusAsync(v, f), + (v, c, r) => c.AsyncSearch.Status(r), + (v, c, r) => c.AsyncSearch.StatusAsync(r), + uniqueValueSelector: values => values.ExtendedValue("id") + ) + }, {GetStep, u => u.Calls>( v => new AsyncSearchGetRequest(v), @@ -95,18 +106,33 @@ public AsyncSearchApiTests(ReadOnlyCluster cluster, EndpointUsage usage) : base( }, }) { } - [I] public async Task AsyncSearchSubmitResponse() => await Assert>(SubmitStep, (v, r) => + [I] public async Task AsyncSearchSubmitResponse() => await Assert>(SubmitStep, r => { r.ShouldBeValid(); r.Response.Should().NotBeNull(); r.Response.Took.Should().BeGreaterOrEqualTo(0); }); + + [I] public async Task AsyncSearchStatusResponse() => await Assert(StatusStep, r => + { + r.ShouldBeValid(); + r.StartTime.Should().BeOnOrBefore(DateTimeOffset.Now); + r.ExpirationTime.Should().BeOnOrAfter(DateTimeOffset.Now); + + if (r.IsRunning) + r.CompletionStatus.HasValue.Should().BeFalse(); + else + r.CompletionStatus?.Should().Be(200); + + r.Shards.Total.Should().BeGreaterOrEqualTo(1); + }); - [I] public async Task AsyncSearchGetResponse() => await Assert>(GetStep, (v, r) => + [I] public async Task AsyncSearchGetResponse() => await Assert>(GetStep, r => { r.ShouldBeValid(); r.Id.Should().NotBeNullOrEmpty(); r.StartTime.Should().BeOnOrBefore(DateTimeOffset.Now); + r.ExpirationTime.Should().BeOnOrAfter(DateTimeOffset.Now); r.Response.Should().NotBeNull(); r.Response.Took.Should().BeGreaterOrEqualTo(0); r.Response.Hits.Should().HaveCount(10); @@ -114,7 +140,7 @@ [I] public async Task AsyncSearchGetResponse() => await Assert await Assert(DeleteStep, (v, r) => + [I] public async Task AsyncSearchDeleteResponse() => await Assert(DeleteStep, r => { r.ShouldBeValid(); r.Acknowledged.Should().BeTrue(); diff --git a/tests/Tests/XPack/AsyncSearch/Status/AsyncSearchStatusUrlTests.cs b/tests/Tests/XPack/AsyncSearch/Status/AsyncSearchStatusUrlTests.cs new file mode 100644 index 00000000000..a993f2a38a7 --- /dev/null +++ b/tests/Tests/XPack/AsyncSearch/Status/AsyncSearchStatusUrlTests.cs @@ -0,0 +1,17 @@ +using System.Threading.Tasks; +using Elastic.Elasticsearch.Xunit.XunitPlumbing; +using Nest; +using Tests.Framework.EndpointTests; +using static Tests.Framework.EndpointTests.UrlTester; + +namespace Tests.XPack.AsyncSearch.Status +{ + public class AsyncSearchStatusUrlTests : UrlTestsBase + { + [U] public override async Task Urls() => await GET("/_async_search/status/search_id") + .Fluent(c => c.AsyncSearch.Status("search_id", f => f)) + .Request(c => c.AsyncSearch.Status(new AsyncSearchStatusRequest("search_id"))) + .FluentAsync(c => c.AsyncSearch.StatusAsync("search_id", f => f)) + .RequestAsync(c => c.AsyncSearch.StatusAsync(new AsyncSearchStatusRequest("search_id"))); + } +}