Skip to content
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

Add NEST support for Query Watcher API #5680

Merged
merged 6 commits into from
May 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/Nest/Descriptors.Watcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,14 @@ protected PutWatchDescriptor(): base()
public PutWatchDescriptor Version(long? version) => Qs("version", version);
}

///<summary>Descriptor for QueryWatches <para>https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html</para></summary>
public partial class QueryWatchesDescriptor : RequestDescriptorBase<QueryWatchesDescriptor, QueryWatchesRequestParameters, IQueryWatchesRequest>, IQueryWatchesRequest
{
internal override ApiUrls ApiUrls => ApiUrlsLookups.WatcherQueryWatches;
// values part of the url path
// Request parameters
}

///<summary>Descriptor for Start <para>https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-start.html</para></summary>
public partial class StartWatcherDescriptor : RequestDescriptorBase<StartWatcherDescriptor, StartWatcherRequestParameters, IStartWatcherRequest>, IStartWatcherRequest
{
Expand Down
24 changes: 24 additions & 0 deletions src/Nest/ElasticClient.Watcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,30 @@ internal WatcherNamespace(ElasticClient client): base(client)
/// </summary>
public Task<PutWatchResponse> PutAsync(IPutWatchRequest request, CancellationToken ct = default) => DoRequestAsync<IPutWatchRequest, PutWatchResponse>(request, request.RequestParameters, ct);
/// <summary>
/// <c>POST</c> request to the <c>watcher.query_watches</c> API, read more about this API online:
/// <para></para>
/// <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>
/// </summary>
public QueryWatchesResponse QueryWatches(Func<QueryWatchesDescriptor, IQueryWatchesRequest> selector = null) => QueryWatches(selector.InvokeOrDefault(new QueryWatchesDescriptor()));
/// <summary>
/// <c>POST</c> request to the <c>watcher.query_watches</c> API, read more about this API online:
/// <para></para>
/// <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>
/// </summary>
public Task<QueryWatchesResponse> QueryWatchesAsync(Func<QueryWatchesDescriptor, IQueryWatchesRequest> selector = null, CancellationToken ct = default) => QueryWatchesAsync(selector.InvokeOrDefault(new QueryWatchesDescriptor()), ct);
/// <summary>
/// <c>POST</c> request to the <c>watcher.query_watches</c> API, read more about this API online:
/// <para></para>
/// <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>
/// </summary>
public QueryWatchesResponse QueryWatches(IQueryWatchesRequest request) => DoRequest<IQueryWatchesRequest, QueryWatchesResponse>(request, request.RequestParameters);
/// <summary>
/// <c>POST</c> request to the <c>watcher.query_watches</c> API, read more about this API online:
/// <para></para>
/// <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>
/// </summary>
public Task<QueryWatchesResponse> QueryWatchesAsync(IQueryWatchesRequest request, CancellationToken ct = default) => DoRequestAsync<IQueryWatchesRequest, QueryWatchesResponse>(request, request.RequestParameters, ct);
/// <summary>
/// <c>POST</c> request to the <c>watcher.start</c> API, read more about this API online:
/// <para></para>
/// <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>
Expand Down
14 changes: 14 additions & 0 deletions src/Nest/Requests.Watcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,20 @@ public long? Version
}
}

[InterfaceDataContract]
public partial interface IQueryWatchesRequest : IRequest<QueryWatchesRequestParameters>
{
}

///<summary>Request for QueryWatches <para>https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html</para></summary>
public partial class QueryWatchesRequest : PlainRequestBase<QueryWatchesRequestParameters>, IQueryWatchesRequest
{
protected IQueryWatchesRequest Self => this;
internal override ApiUrls ApiUrls => ApiUrlsLookups.WatcherQueryWatches;
// values part of the url path
// Request parameters
}

[InterfaceDataContract]
public partial interface IStartWatcherRequest : IRequest<StartWatcherRequestParameters>
{
Expand Down
98 changes: 98 additions & 0 deletions src/Nest/XPack/Watcher/Query/QueryWatchesRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// 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;

namespace Nest
{
[MapsApi("watcher.query_watches.json")]
[ReadAs(typeof(QueryWatchesRequest))]
public partial interface IQueryWatchesRequest
{
/// <summary>
/// The offset from the first result to fetch. Needs to be non-negative.
/// </summary>
[DataMember(Name = "from")]
int? From { get; set; }

/// <summary>
/// Optional, query filter watches to be returned.
/// </summary>
[DataMember(Name = "query")]
QueryContainer Query { get; set; }

/// <summary>
/// Sort values that can be used to start returning results "after" any document in the result list.
/// </summary>
[DataMember(Name = "search_after")]
IList<object> SearchAfter { get; set; }

/// <summary>
/// The number of hits to return. Defaults to 10.
/// </summary>
[DataMember(Name = "size")]
int? Size { get; set; }

/// <summary>
/// Specifies how to sort the search hits.
/// </summary>
[DataMember(Name = "sort")]
IList<ISort> Sort { get; set; }
}

/// <inheritdoc cref="IQueryWatchesRequest" />
public partial class QueryWatchesRequest
{
/// <inheritdoc />
public int? From { get; set; }

/// <inheritdoc />
public QueryContainer Query { get; set; }

/// <inheritdoc />
public IList<object> SearchAfter { get; set; }

/// <inheritdoc />
public int? Size { get; set; }

/// <inheritdoc />
public IList<ISort> Sort { get; set; }
}

/// <inheritdoc cref="IQueryWatchesRequest" />
public partial class QueryWatchesDescriptor
{
int? IQueryWatchesRequest.From { get; set; }
QueryContainer IQueryWatchesRequest.Query { get; set; }
IList<object> IQueryWatchesRequest.SearchAfter { get; set; }
int? IQueryWatchesRequest.Size { get; set; }
IList<ISort> IQueryWatchesRequest.Sort { get; set; }

/// <inheritdoc cref="IQueryWatchesRequest.From" />
public QueryWatchesDescriptor From(int? from) => Assign(from, (a, v) => a.From = v);

/// <inheritdoc cref="IQueryWatchesRequest.Query" />
public QueryWatchesDescriptor Query(Func<QueryContainerDescriptor<Watch>, QueryContainer> query) =>
Assign(query, (a, v) => a.Query = v?.Invoke(new QueryContainerDescriptor<Watch>()));

/// <inheritdoc cref="IQueryWatchesRequest.SearchAfter" />
public QueryWatchesDescriptor SearchAfter(IEnumerable<object> searchAfter) =>
Assign(searchAfter, (a, v) => a.SearchAfter = v?.ToListOrNullIfEmpty());

/// <inheritdoc cref="IQueryWatchesRequest.SearchAfter" />
public QueryWatchesDescriptor SearchAfter(IList<object> searchAfter) => Assign(searchAfter, (a, v) => a.SearchAfter = v);

/// <inheritdoc cref="IQueryWatchesRequest.SearchAfter" />
public QueryWatchesDescriptor SearchAfter(params object[] searchAfter) => Assign(searchAfter, (a, v) => a.SearchAfter = v);

/// <inheritdoc cref="IQueryWatchesRequest.Size" />
public QueryWatchesDescriptor Size(int? size) => Assign(size, (a, v) => a.Size = v);

/// <inheritdoc cref="IQueryWatchesRequest.Sort" />
public QueryWatchesDescriptor Sort(Func<SortDescriptor<Watch>, IPromise<IList<ISort>>> selector) =>
Assign(selector, (a, v) => a.Sort = v?.Invoke(new SortDescriptor<Watch>())?.Value);
}
}
37 changes: 37 additions & 0 deletions src/Nest/XPack/Watcher/Query/QueryWatchesResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// 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.Runtime.Serialization;

namespace Nest
{
public class QueryWatchesResponse : ResponseBase
{
[DataMember(Name = "count")]
public int Count { get; internal set; }

[DataMember(Name = "watches")]
public IReadOnlyCollection<WatchQueryResult> Watches { get; internal set; }
}

[DataContract]
public class WatchQueryResult
{
[DataMember(Name = "_id")]
public string Id { get; set; }

[DataMember(Name = "_primary_term")]
public int PrimaryTerm { get; set; }

[DataMember(Name = "_seq_no")]
public int SequenceNumber { get; set; }

[DataMember(Name = "status")]
public WatchStatus Status { get; set; }

[DataMember(Name = "watch")]
public IWatch Watch { get; set; }
}
}
1 change: 1 addition & 0 deletions src/Nest/_Generated/ApiUrlsLookup.generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ internal static class ApiUrlsLookups
internal static ApiUrls WatcherExecute = new ApiUrls(new[]{"_watcher/watch/{id}/_execute", "_watcher/watch/_execute"});
internal static ApiUrls WatcherGet = new ApiUrls(new[]{"_watcher/watch/{id}"});
internal static ApiUrls WatcherPut = new ApiUrls(new[]{"_watcher/watch/{id}"});
internal static ApiUrls WatcherQueryWatches = new ApiUrls(new[]{"_watcher/_query/watches"});
internal static ApiUrls WatcherStart = new ApiUrls(new[]{"_watcher/_start"});
internal static ApiUrls WatcherStats = new ApiUrls(new[]{"_watcher/stats", "_watcher/stats/{metric}"});
internal static ApiUrls WatcherStop = new ApiUrls(new[]{"_watcher/_stop"});
Expand Down
104 changes: 104 additions & 0 deletions tests/Tests/XPack/Watcher/QueryWatches/QueryWatchesApiTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// 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 Elasticsearch.Net;
using FluentAssertions;
using Nest;
using Tests.Framework.EndpointTests;
using Tests.Framework.EndpointTests.TestState;

namespace Tests.XPack.Watcher.QueryWatches
{
public class QueryWatchesApiTests
: ApiIntegrationTestBase<WatcherCluster, QueryWatchesResponse, IQueryWatchesRequest, QueryWatchesDescriptor, QueryWatchesRequest>
{
private readonly Dictionary<string, object> _termCondition = new() { { "metadata.name", new { value = "value" } } };

public QueryWatchesApiTests(WatcherCluster cluster, EndpointUsage usage) : base(cluster, usage) { }

protected override bool ExpectIsValid => true;

protected override object ExpectJson => new
{
size = 5, from = 0, query = new { term = _termCondition }, sort = new[] { new { _id = new { order = "asc" } } }
};

protected override int ExpectStatusCode => 200;

protected override Func<QueryWatchesDescriptor, IQueryWatchesRequest> Fluent => p => p
.From(0)
.Size(5)
.Sort(s => s.Ascending("_id"))
.Query(q => q.Term(t => t.Field("metadata.name").Value("value")));

protected override HttpMethod HttpMethod => HttpMethod.POST;

protected override QueryWatchesRequest Initializer => new()
{
From = 0,
Size = 5,
Sort = new List<ISort> { new FieldSort { Field = "_id", Order = SortOrder.Ascending } },
Query = new TermQuery { Field = "metadata.name", Value = "value" }
};

protected override string UrlPath => "/_watcher/_query/watches";

protected override void IntegrationSetup(IElasticClient client, CallUniqueValues values)
{
foreach (var callUniqueValue in values)
{
var putWatchResponse = client.Watcher.Put(callUniqueValue.Value, p => p
.Input(i => i
.Simple(s => s
.Add("key", "value")
)
)
.Trigger(t => t
.Schedule(s => s
.Cron("0 5 9 * * ?")
)
)
.Actions(a => a
.Email("reminder_email", e => e
.To("[email protected]")
.Subject("Something's strange in the neighbourhood")
.Body(b => b
.Text("Who you gonna call?")
)
)
)
.Metadata(m => m.Add("name", "value"))
);

if (!putWatchResponse.IsValid)
throw new Exception("Problem setting up integration test");
}
}

protected override LazyResponses ClientUsage() => Calls(
(client, f) => client.Watcher.QueryWatches(f),
(client, f) => client.Watcher.QueryWatchesAsync(f),
(client, r) => client.Watcher.QueryWatches(r),
(client, r) => client.Watcher.QueryWatchesAsync(r)
);

protected override void ExpectResponse(QueryWatchesResponse response)
{
response.IsValid.Should().BeTrue();
response.Count.Should().Be(4);
response.Watches.Count.Should().Be(4);

foreach (var watchResult in response.Watches)
{
watchResult.Id.Should().NotBeNullOrEmpty();
watchResult.SequenceNumber.Should().BeGreaterOrEqualTo(0);
watchResult.PrimaryTerm.Should().Be(1);
watchResult.Status.State.Active.Should().BeTrue();
watchResult.Watch.Metadata["name"].Should().Be("value");
}
}
}
}
21 changes: 21 additions & 0 deletions tests/Tests/XPack/Watcher/QueryWatches/QueryWatchesUrlTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// 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.Threading.Tasks;
using Elastic.Elasticsearch.Xunit.XunitPlumbing;
using Nest;
using Tests.Framework.EndpointTests;
using static Tests.Framework.EndpointTests.UrlTester;

namespace Tests.XPack.Watcher.QueryWatches
{
public class QueryWatchesUrlTests : UrlTestsBase
{
[U] public override async Task Urls() => await POST("/_watcher/_query/watches")
.Fluent(c => c.Watcher.QueryWatches())
.Request(c => c.Watcher.QueryWatches(new QueryWatchesRequest()))
.FluentAsync(c => c.Watcher.QueryWatchesAsync())
.RequestAsync(c => c.Watcher.QueryWatchesAsync(new QueryWatchesRequest()));
}
}