Skip to content

Commit a308b6f

Browse files
stevejgordongithub-actions[bot]
authored andcommitted
Add NEST support for Query Watcher API (#5680)
* Add request and response * Update request * Generate code * Update request properties * Update request and response * Add tests
1 parent 7446245 commit a308b6f

File tree

8 files changed

+307
-0
lines changed

8 files changed

+307
-0
lines changed

src/Nest/Descriptors.Watcher.cs

+8
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,14 @@ protected PutWatchDescriptor(): base()
201201
public PutWatchDescriptor Version(long? version) => Qs("version", version);
202202
}
203203

204+
///<summary>Descriptor for QueryWatches <para>https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html</para></summary>
205+
public partial class QueryWatchesDescriptor : RequestDescriptorBase<QueryWatchesDescriptor, QueryWatchesRequestParameters, IQueryWatchesRequest>, IQueryWatchesRequest
206+
{
207+
internal override ApiUrls ApiUrls => ApiUrlsLookups.WatcherQueryWatches;
208+
// values part of the url path
209+
// Request parameters
210+
}
211+
204212
///<summary>Descriptor for Start <para>https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-start.html</para></summary>
205213
public partial class StartWatcherDescriptor : RequestDescriptorBase<StartWatcherDescriptor, StartWatcherRequestParameters, IStartWatcherRequest>, IStartWatcherRequest
206214
{

src/Nest/ElasticClient.Watcher.cs

+24
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,30 @@ internal WatcherNamespace(ElasticClient client): base(client)
208208
/// </summary>
209209
public Task<PutWatchResponse> PutAsync(IPutWatchRequest request, CancellationToken ct = default) => DoRequestAsync<IPutWatchRequest, PutWatchResponse>(request, request.RequestParameters, ct);
210210
/// <summary>
211+
/// <c>POST</c> request to the <c>watcher.query_watches</c> API, read more about this API online:
212+
/// <para></para>
213+
/// <a href = "https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html</a>
214+
/// </summary>
215+
public QueryWatchesResponse QueryWatches(Func<QueryWatchesDescriptor, IQueryWatchesRequest> selector = null) => QueryWatches(selector.InvokeOrDefault(new QueryWatchesDescriptor()));
216+
/// <summary>
217+
/// <c>POST</c> request to the <c>watcher.query_watches</c> API, read more about this API online:
218+
/// <para></para>
219+
/// <a href = "https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html</a>
220+
/// </summary>
221+
public Task<QueryWatchesResponse> QueryWatchesAsync(Func<QueryWatchesDescriptor, IQueryWatchesRequest> selector = null, CancellationToken ct = default) => QueryWatchesAsync(selector.InvokeOrDefault(new QueryWatchesDescriptor()), ct);
222+
/// <summary>
223+
/// <c>POST</c> request to the <c>watcher.query_watches</c> API, read more about this API online:
224+
/// <para></para>
225+
/// <a href = "https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html</a>
226+
/// </summary>
227+
public QueryWatchesResponse QueryWatches(IQueryWatchesRequest request) => DoRequest<IQueryWatchesRequest, QueryWatchesResponse>(request, request.RequestParameters);
228+
/// <summary>
229+
/// <c>POST</c> request to the <c>watcher.query_watches</c> API, read more about this API online:
230+
/// <para></para>
231+
/// <a href = "https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html</a>
232+
/// </summary>
233+
public Task<QueryWatchesResponse> QueryWatchesAsync(IQueryWatchesRequest request, CancellationToken ct = default) => DoRequestAsync<IQueryWatchesRequest, QueryWatchesResponse>(request, request.RequestParameters, ct);
234+
/// <summary>
211235
/// <c>POST</c> request to the <c>watcher.start</c> API, read more about this API online:
212236
/// <para></para>
213237
/// <a href = "https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-start.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-start.html</a>

src/Nest/Requests.Watcher.cs

+14
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,20 @@ public long? Version
312312
}
313313
}
314314

315+
[InterfaceDataContract]
316+
public partial interface IQueryWatchesRequest : IRequest<QueryWatchesRequestParameters>
317+
{
318+
}
319+
320+
///<summary>Request for QueryWatches <para>https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html</para></summary>
321+
public partial class QueryWatchesRequest : PlainRequestBase<QueryWatchesRequestParameters>, IQueryWatchesRequest
322+
{
323+
protected IQueryWatchesRequest Self => this;
324+
internal override ApiUrls ApiUrls => ApiUrlsLookups.WatcherQueryWatches;
325+
// values part of the url path
326+
// Request parameters
327+
}
328+
315329
[InterfaceDataContract]
316330
public partial interface IStartWatcherRequest : IRequest<StartWatcherRequestParameters>
317331
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Runtime.Serialization;
8+
9+
namespace Nest
10+
{
11+
[MapsApi("watcher.query_watches.json")]
12+
[ReadAs(typeof(QueryWatchesRequest))]
13+
public partial interface IQueryWatchesRequest
14+
{
15+
/// <summary>
16+
/// The offset from the first result to fetch. Needs to be non-negative.
17+
/// </summary>
18+
[DataMember(Name = "from")]
19+
int? From { get; set; }
20+
21+
/// <summary>
22+
/// Optional, query filter watches to be returned.
23+
/// </summary>
24+
[DataMember(Name = "query")]
25+
QueryContainer Query { get; set; }
26+
27+
/// <summary>
28+
/// Sort values that can be used to start returning results "after" any document in the result list.
29+
/// </summary>
30+
[DataMember(Name = "search_after")]
31+
IList<object> SearchAfter { get; set; }
32+
33+
/// <summary>
34+
/// The number of hits to return. Defaults to 10.
35+
/// </summary>
36+
[DataMember(Name = "size")]
37+
int? Size { get; set; }
38+
39+
/// <summary>
40+
/// Specifies how to sort the search hits.
41+
/// </summary>
42+
[DataMember(Name = "sort")]
43+
IList<ISort> Sort { get; set; }
44+
}
45+
46+
/// <inheritdoc cref="IQueryWatchesRequest" />
47+
public partial class QueryWatchesRequest
48+
{
49+
/// <inheritdoc />
50+
public int? From { get; set; }
51+
52+
/// <inheritdoc />
53+
public QueryContainer Query { get; set; }
54+
55+
/// <inheritdoc />
56+
public IList<object> SearchAfter { get; set; }
57+
58+
/// <inheritdoc />
59+
public int? Size { get; set; }
60+
61+
/// <inheritdoc />
62+
public IList<ISort> Sort { get; set; }
63+
}
64+
65+
/// <inheritdoc cref="IQueryWatchesRequest" />
66+
public partial class QueryWatchesDescriptor
67+
{
68+
int? IQueryWatchesRequest.From { get; set; }
69+
QueryContainer IQueryWatchesRequest.Query { get; set; }
70+
IList<object> IQueryWatchesRequest.SearchAfter { get; set; }
71+
int? IQueryWatchesRequest.Size { get; set; }
72+
IList<ISort> IQueryWatchesRequest.Sort { get; set; }
73+
74+
/// <inheritdoc cref="IQueryWatchesRequest.From" />
75+
public QueryWatchesDescriptor From(int? from) => Assign(from, (a, v) => a.From = v);
76+
77+
/// <inheritdoc cref="IQueryWatchesRequest.Query" />
78+
public QueryWatchesDescriptor Query(Func<QueryContainerDescriptor<Watch>, QueryContainer> query) =>
79+
Assign(query, (a, v) => a.Query = v?.Invoke(new QueryContainerDescriptor<Watch>()));
80+
81+
/// <inheritdoc cref="IQueryWatchesRequest.SearchAfter" />
82+
public QueryWatchesDescriptor SearchAfter(IEnumerable<object> searchAfter) =>
83+
Assign(searchAfter, (a, v) => a.SearchAfter = v?.ToListOrNullIfEmpty());
84+
85+
/// <inheritdoc cref="IQueryWatchesRequest.SearchAfter" />
86+
public QueryWatchesDescriptor SearchAfter(IList<object> searchAfter) => Assign(searchAfter, (a, v) => a.SearchAfter = v);
87+
88+
/// <inheritdoc cref="IQueryWatchesRequest.SearchAfter" />
89+
public QueryWatchesDescriptor SearchAfter(params object[] searchAfter) => Assign(searchAfter, (a, v) => a.SearchAfter = v);
90+
91+
/// <inheritdoc cref="IQueryWatchesRequest.Size" />
92+
public QueryWatchesDescriptor Size(int? size) => Assign(size, (a, v) => a.Size = v);
93+
94+
/// <inheritdoc cref="IQueryWatchesRequest.Sort" />
95+
public QueryWatchesDescriptor Sort(Func<SortDescriptor<Watch>, IPromise<IList<ISort>>> selector) =>
96+
Assign(selector, (a, v) => a.Sort = v?.Invoke(new SortDescriptor<Watch>())?.Value);
97+
}
98+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
using System.Collections.Generic;
6+
using System.Runtime.Serialization;
7+
8+
namespace Nest
9+
{
10+
public class QueryWatchesResponse : ResponseBase
11+
{
12+
[DataMember(Name = "count")]
13+
public int Count { get; internal set; }
14+
15+
[DataMember(Name = "watches")]
16+
public IReadOnlyCollection<WatchQueryResult> Watches { get; internal set; }
17+
}
18+
19+
[DataContract]
20+
public class WatchQueryResult
21+
{
22+
[DataMember(Name = "_id")]
23+
public string Id { get; set; }
24+
25+
[DataMember(Name = "_primary_term")]
26+
public int PrimaryTerm { get; set; }
27+
28+
[DataMember(Name = "_seq_no")]
29+
public int SequenceNumber { get; set; }
30+
31+
[DataMember(Name = "status")]
32+
public WatchStatus Status { get; set; }
33+
34+
[DataMember(Name = "watch")]
35+
public IWatch Watch { get; set; }
36+
}
37+
}

src/Nest/_Generated/ApiUrlsLookup.generated.cs

+1
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ internal static class ApiUrlsLookups
324324
internal static ApiUrls WatcherExecute = new ApiUrls(new[]{"_watcher/watch/{id}/_execute", "_watcher/watch/_execute"});
325325
internal static ApiUrls WatcherGet = new ApiUrls(new[]{"_watcher/watch/{id}"});
326326
internal static ApiUrls WatcherPut = new ApiUrls(new[]{"_watcher/watch/{id}"});
327+
internal static ApiUrls WatcherQueryWatches = new ApiUrls(new[]{"_watcher/_query/watches"});
327328
internal static ApiUrls WatcherStart = new ApiUrls(new[]{"_watcher/_start"});
328329
internal static ApiUrls WatcherStats = new ApiUrls(new[]{"_watcher/stats", "_watcher/stats/{metric}"});
329330
internal static ApiUrls WatcherStop = new ApiUrls(new[]{"_watcher/_stop"});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using Elasticsearch.Net;
8+
using FluentAssertions;
9+
using Nest;
10+
using Tests.Framework.EndpointTests;
11+
using Tests.Framework.EndpointTests.TestState;
12+
13+
namespace Tests.XPack.Watcher.QueryWatches
14+
{
15+
public class QueryWatchesApiTests
16+
: ApiIntegrationTestBase<WatcherCluster, QueryWatchesResponse, IQueryWatchesRequest, QueryWatchesDescriptor, QueryWatchesRequest>
17+
{
18+
private readonly Dictionary<string, object> _termCondition = new() { { "metadata.name", new { value = "value" } } };
19+
20+
public QueryWatchesApiTests(WatcherCluster cluster, EndpointUsage usage) : base(cluster, usage) { }
21+
22+
protected override bool ExpectIsValid => true;
23+
24+
protected override object ExpectJson => new
25+
{
26+
size = 5, from = 0, query = new { term = _termCondition }, sort = new[] { new { _id = new { order = "asc" } } }
27+
};
28+
29+
protected override int ExpectStatusCode => 200;
30+
31+
protected override Func<QueryWatchesDescriptor, IQueryWatchesRequest> Fluent => p => p
32+
.From(0)
33+
.Size(5)
34+
.Sort(s => s.Ascending("_id"))
35+
.Query(q => q.Term(t => t.Field("metadata.name").Value("value")));
36+
37+
protected override HttpMethod HttpMethod => HttpMethod.POST;
38+
39+
protected override QueryWatchesRequest Initializer => new()
40+
{
41+
From = 0,
42+
Size = 5,
43+
Sort = new List<ISort> { new FieldSort { Field = "_id", Order = SortOrder.Ascending } },
44+
Query = new TermQuery { Field = "metadata.name", Value = "value" }
45+
};
46+
47+
protected override string UrlPath => "/_watcher/_query/watches";
48+
49+
protected override void IntegrationSetup(IElasticClient client, CallUniqueValues values)
50+
{
51+
foreach (var callUniqueValue in values)
52+
{
53+
var putWatchResponse = client.Watcher.Put(callUniqueValue.Value, p => p
54+
.Input(i => i
55+
.Simple(s => s
56+
.Add("key", "value")
57+
)
58+
)
59+
.Trigger(t => t
60+
.Schedule(s => s
61+
.Cron("0 5 9 * * ?")
62+
)
63+
)
64+
.Actions(a => a
65+
.Email("reminder_email", e => e
66+
67+
.Subject("Something's strange in the neighbourhood")
68+
.Body(b => b
69+
.Text("Who you gonna call?")
70+
)
71+
)
72+
)
73+
.Metadata(m => m.Add("name", "value"))
74+
);
75+
76+
if (!putWatchResponse.IsValid)
77+
throw new Exception("Problem setting up integration test");
78+
}
79+
}
80+
81+
protected override LazyResponses ClientUsage() => Calls(
82+
(client, f) => client.Watcher.QueryWatches(f),
83+
(client, f) => client.Watcher.QueryWatchesAsync(f),
84+
(client, r) => client.Watcher.QueryWatches(r),
85+
(client, r) => client.Watcher.QueryWatchesAsync(r)
86+
);
87+
88+
protected override void ExpectResponse(QueryWatchesResponse response)
89+
{
90+
response.IsValid.Should().BeTrue();
91+
response.Count.Should().Be(4);
92+
response.Watches.Count.Should().Be(4);
93+
94+
foreach (var watchResult in response.Watches)
95+
{
96+
watchResult.Id.Should().NotBeNullOrEmpty();
97+
watchResult.SequenceNumber.Should().BeGreaterOrEqualTo(0);
98+
watchResult.PrimaryTerm.Should().Be(1);
99+
watchResult.Status.State.Active.Should().BeTrue();
100+
watchResult.Watch.Metadata["name"].Should().Be("value");
101+
}
102+
}
103+
}
104+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
using System.Threading.Tasks;
6+
using Elastic.Elasticsearch.Xunit.XunitPlumbing;
7+
using Nest;
8+
using Tests.Framework.EndpointTests;
9+
using static Tests.Framework.EndpointTests.UrlTester;
10+
11+
namespace Tests.XPack.Watcher.QueryWatches
12+
{
13+
public class QueryWatchesUrlTests : UrlTestsBase
14+
{
15+
[U] public override async Task Urls() => await POST("/_watcher/_query/watches")
16+
.Fluent(c => c.Watcher.QueryWatches())
17+
.Request(c => c.Watcher.QueryWatches(new QueryWatchesRequest()))
18+
.FluentAsync(c => c.Watcher.QueryWatchesAsync())
19+
.RequestAsync(c => c.Watcher.QueryWatchesAsync(new QueryWatchesRequest()));
20+
}
21+
}

0 commit comments

Comments
 (0)