Skip to content

Commit

Permalink
Delete forecast API (#3591)
Browse files Browse the repository at this point in the history
Implement Delete Forecast API + integration tests
  • Loading branch information
Stuart Cam authored and russcam committed Mar 21, 2019
1 parent c1a705a commit e1a2a13
Show file tree
Hide file tree
Showing 20 changed files with 436 additions and 21 deletions.
1 change: 0 additions & 1 deletion src/CodeGeneration/ApiGenerator/ApiGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ public class ApiGenerator
"rank_eval.json",

// these API's are new and need to be mapped
"xpack.ml.delete_forecast.json",
"xpack.ml.find_file_structure.json",
};

Expand Down
1 change: 1 addition & 0 deletions src/CodeGeneration/ApiGenerator/Domain/ApiUrlPart.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public string ClrTypeName
case "filter_id":
case "id": return Type == "string" ? "Id" : "Ids";
case "category_id": return "CategoryId";
case "forecast_id": return "ForecastIds";
case "nodes":
case "node_id": return Type == "string" ? "NodeId" : "NodeIds";
case "scroll_id": return Type == "string" ? "ScrollId" : "ScrollIds";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"xpack.ml.delete_forecast": {
"url": {
"path": "/_xpack/ml/anomaly_detectors/{job_id}/_forecast/{forecast_id}",
"paths": [
"/_xpack/ml/anomaly_detectors/{job_id}/_forecast/{forecast_id}"
],
"parts": {
"forecast_id": {
"required": true,
"description": "The ID of the forecast to delete, can be comma delimited list or `_all`"
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2395,6 +2395,15 @@ public partial class DeleteExpiredDataRequestParameters : RequestParameters<Dele
{
public override HttpMethod DefaultHttpMethod => HttpMethod.DELETE;
}
///<summary>Request options for XpackMlDeleteForecast<pre>http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-forecast.html</pre></summary>
public partial class DeleteForecastRequestParameters : RequestParameters<DeleteForecastRequestParameters>
{
public override HttpMethod DefaultHttpMethod => HttpMethod.DELETE;
///<summary>Whether to ignore if `_all` matches no forecasts</summary>
public bool? AllowNoForecasts { get => Q<bool?>("allow_no_forecasts"); set => Q("allow_no_forecasts", value); }
///<summary>Controls the time to wait until the forecast(s) are deleted. Default to 30 seconds</summary>
public TimeSpan Timeout { get => Q<TimeSpan>("timeout"); set => Q("timeout", value); }
}
///<summary>Request options for XpackMlDeleteJob<pre>http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-job.html</pre></summary>
public partial class DeleteJobRequestParameters : RequestParameters<DeleteJobRequestParameters>
{
Expand Down
12 changes: 12 additions & 0 deletions src/Elasticsearch.Net/ElasticLowLevelClient.Generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3236,6 +3236,18 @@ public TResponse XpackMlDeleteExpiredData<TResponse>(DeleteExpiredDataRequestPar
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
public Task<TResponse> XpackMlDeleteExpiredDataAsync<TResponse>(DeleteExpiredDataRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken))
where TResponse : class, IElasticsearchResponse, new() => this.DoRequestAsync<TResponse>(DELETE, Url($"_xpack/ml/_delete_expired_data"), ctx, null, _params(requestParameters));
///<summary>DELETE on /_xpack/ml/anomaly_detectors/{job_id}/_forecast/{forecast_id} <para>http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-forecast.html</para></summary>
///<param name="job_id">The ID of the job from which to delete forecasts</param>
///<param name="forecast_id">The ID of the forecast to delete, can be comma delimited list or `_all`</param>
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
public TResponse XpackMlDeleteForecast<TResponse>(string job_id, string forecast_id, DeleteForecastRequestParameters requestParameters = null)
where TResponse : class, IElasticsearchResponse, new() => this.DoRequest<TResponse>(DELETE, Url($"_xpack/ml/anomaly_detectors/{job_id.NotNull("job_id")}/_forecast/{forecast_id.NotNull("forecast_id")}"), null, _params(requestParameters));
///<summary>DELETE on /_xpack/ml/anomaly_detectors/{job_id}/_forecast/{forecast_id} <para>http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-forecast.html</para></summary>
///<param name="job_id">The ID of the job from which to delete forecasts</param>
///<param name="forecast_id">The ID of the forecast to delete, can be comma delimited list or `_all`</param>
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
public Task<TResponse> XpackMlDeleteForecastAsync<TResponse>(string job_id, string forecast_id, DeleteForecastRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken))
where TResponse : class, IElasticsearchResponse, new() => this.DoRequestAsync<TResponse>(DELETE, Url($"_xpack/ml/anomaly_detectors/{job_id.NotNull("job_id")}/_forecast/{forecast_id.NotNull("forecast_id")}"), ctx, null, _params(requestParameters));
///<summary>DELETE on /_xpack/ml/anomaly_detectors/{job_id} <para>http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-job.html</para></summary>
///<param name="job_id">The ID of the job to delete</param>
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
Expand Down
10 changes: 10 additions & 0 deletions src/Elasticsearch.Net/IElasticLowLevelClient.Generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2620,6 +2620,16 @@ public partial interface IElasticLowLevelClient
///<summary>DELETE on /_xpack/ml/_delete_expired_data <para></para></summary>
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
Task<TResponse> XpackMlDeleteExpiredDataAsync<TResponse>(DeleteExpiredDataRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) where TResponse : class, IElasticsearchResponse, new();
///<summary>DELETE on /_xpack/ml/anomaly_detectors/{job_id}/_forecast/{forecast_id} <para>http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-forecast.html</para></summary>
///<param name="job_id">The ID of the job from which to delete forecasts</param>
///<param name="forecast_id">The ID of the forecast to delete, can be comma delimited list or `_all`</param>
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
TResponse XpackMlDeleteForecast<TResponse>(string job_id, string forecast_id, DeleteForecastRequestParameters requestParameters = null) where TResponse : class, IElasticsearchResponse, new();
///<summary>DELETE on /_xpack/ml/anomaly_detectors/{job_id}/_forecast/{forecast_id} <para>http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-forecast.html</para></summary>
///<param name="job_id">The ID of the job from which to delete forecasts</param>
///<param name="forecast_id">The ID of the forecast to delete, can be comma delimited list or `_all`</param>
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
Task<TResponse> XpackMlDeleteForecastAsync<TResponse>(string job_id, string forecast_id, DeleteForecastRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) where TResponse : class, IElasticsearchResponse, new();
///<summary>DELETE on /_xpack/ml/anomaly_detectors/{job_id} <para>http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-job.html</para></summary>
///<param name="job_id">The ID of the job to delete</param>
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
Expand Down
61 changes: 61 additions & 0 deletions src/Nest/CommonAbstractions/Infer/ForecastIds/ForecastIds.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Elasticsearch.Net;

namespace Nest
{
[DebuggerDisplay("{DebugDisplay,nq}")]
public class ForecastIds : IUrlParameter, IEquatable<ForecastIds>
{
public static ForecastIds All { get; } = new ForecastIds("_all");

private readonly List<string> _forecastIds;

public ForecastIds(IEnumerable<string> forecastIds) => _forecastIds = forecastIds?.ToList();

public ForecastIds(string forecastIds)
{
if (!forecastIds.IsNullOrEmptyCommaSeparatedList(out var ids))
_forecastIds = ids.ToList();
}

private string DebugDisplay => ((IUrlParameter)this).GetString(null);

public bool Equals(ForecastIds other)
{
if (other == null) return false;
if (_forecastIds == null && other._forecastIds == null) return true;
if (_forecastIds == null || other._forecastIds == null) return false;

return _forecastIds.Count == other._forecastIds.Count &&
_forecastIds.OrderBy(id => id).SequenceEqual(other._forecastIds.OrderBy(id => id));
}

string IUrlParameter.GetString(IConnectionConfigurationValues settings) => string.Join(",", _forecastIds ?? Enumerable.Empty<string>());

public static implicit operator ForecastIds(string forecastIds) =>
forecastIds.IsNullOrEmptyCommaSeparatedList(out var arr) ? null : new ForecastIds(arr);

public static implicit operator ForecastIds(string[] forecastIds) =>
forecastIds.IsEmpty() ? null : new ForecastIds(forecastIds);

public override bool Equals(object obj) => obj is ForecastIds other && Equals(other);

public override int GetHashCode()
{
unchecked
{
var hc = 0;
foreach (var id in _forecastIds.OrderBy(id => id))
hc = hc * 17 + id.GetHashCode();
return hc;
}
}

public static bool operator ==(ForecastIds left, ForecastIds right) => Equals(left, right);

public static bool operator !=(ForecastIds left, ForecastIds right) => !Equals(left, right);
}
}
1 change: 1 addition & 0 deletions src/Nest/CommonAbstractions/Request/RouteValues.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public class RouteValues
public string ActionId => GetResolved("action_id");
public string Alias => GetResolved("alias");
public string CategoryId => GetResolved("category_id");
public string ForecastId => GetResolved("forecast_id");
public string Context => GetResolved("context");
public string DatafeedId => GetResolved("datafeed_id");
public string Feature => GetResolved("feature");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Nest
{
public partial interface IDeleteForecastRequest { }

public partial class DeleteForecastRequest { }

[DescriptorFor("XpackMlDeleteForecast")]
public partial class DeleteForecastDescriptor { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Nest
{
public interface IDeleteForecastResponse : IAcknowledgedResponse { }

public class DeleteForecastResponse : AcknowledgedResponseBase, IDeleteForecastResponse { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Elasticsearch.Net;

namespace Nest
{
public partial interface IElasticClient
{
/// <summary>
/// Deletes forecasts from a machine learning job.
/// </summary>
IDeleteForecastResponse DeleteForecast(Id jobId, ForecastIds forecastId, Func<DeleteForecastDescriptor, IDeleteForecastRequest> selector = null);

/// <inheritdoc cref="DeleteForecast(Nest.Id,Nest.ForecastIds,System.Func{Nest.DeleteForecastDescriptor,Nest.IDeleteForecastRequest})" />
IDeleteForecastResponse DeleteForecast(IDeleteForecastRequest request);

/// <inheritdoc cref="DeleteForecast(Nest.Id,Nest.ForecastIds,System.Func{Nest.DeleteForecastDescriptor,Nest.IDeleteForecastRequest})" />
Task<IDeleteForecastResponse> DeleteForecastAsync(Id jobId, ForecastIds forecastId, Func<DeleteForecastDescriptor, IDeleteForecastRequest> selector = null,
CancellationToken cancellationToken = default(CancellationToken)
);

/// <inheritdoc cref="DeleteForecast(Nest.Id,Nest.ForecastIds,System.Func{Nest.DeleteForecastDescriptor,Nest.IDeleteForecastRequest})" />
Task<IDeleteForecastResponse> DeleteForecastAsync(IDeleteForecastRequest request,
CancellationToken cancellationToken = default(CancellationToken)
);
}

public partial class ElasticClient
{
/// <inheritdoc cref="DeleteForecast(Nest.Id,Nest.ForecastIds,System.Func{Nest.DeleteForecastDescriptor,Nest.IDeleteForecastRequest})" />
public IDeleteForecastResponse DeleteForecast(Id jobId, ForecastIds forecastId, Func<DeleteForecastDescriptor, IDeleteForecastRequest> selector = null) =>
DeleteForecast(selector.InvokeOrDefault(new DeleteForecastDescriptor(jobId, forecastId)));

/// <inheritdoc cref="DeleteForecast(Nest.Id,Nest.ForecastIds,System.Func{Nest.DeleteForecastDescriptor,Nest.IDeleteForecastRequest})" />
public IDeleteForecastResponse DeleteForecast(IDeleteForecastRequest request) =>
Dispatcher.Dispatch<IDeleteForecastRequest, DeleteForecastRequestParameters, DeleteForecastResponse>(
request,
(p, d) => LowLevelDispatch.XpackMlDeleteForecastDispatch<DeleteForecastResponse>(p)
);

/// <inheritdoc cref="DeleteForecast(Nest.Id,Nest.ForecastIds,System.Func{Nest.DeleteForecastDescriptor,Nest.IDeleteForecastRequest})" />
public Task<IDeleteForecastResponse> DeleteForecastAsync(Id jobId, ForecastIds forecastId,
Func<DeleteForecastDescriptor, IDeleteForecastRequest> selector = null, CancellationToken cancellationToken = default(CancellationToken)) =>
DeleteForecastAsync(selector.InvokeOrDefault(new DeleteForecastDescriptor(jobId, forecastId)), cancellationToken);

/// <inheritdoc cref="DeleteForecast(Nest.Id,Nest.ForecastIds,System.Func{Nest.DeleteForecastDescriptor,Nest.IDeleteForecastRequest})" />
public Task<IDeleteForecastResponse> DeleteForecastAsync(IDeleteForecastRequest request,
CancellationToken cancellationToken = default(CancellationToken)) =>
Dispatcher.DispatchAsync<IDeleteForecastRequest, DeleteForecastRequestParameters, DeleteForecastResponse, IDeleteForecastResponse>(
request,
cancellationToken,
(p, d, c) => LowLevelDispatch.XpackMlDeleteForecastDispatchAsync<DeleteForecastResponse>(p, c)
);
}
}
18 changes: 18 additions & 0 deletions src/Nest/_Generated/_Descriptors.generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4232,6 +4232,24 @@ public partial class DeleteExpiredDataDescriptor : RequestDescriptorBase<Delete
// Request parameters

}
///<summary>descriptor for XpackMlDeleteForecast <pre>http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-forecast.html</pre></summary>
public partial class DeleteForecastDescriptor : RequestDescriptorBase<DeleteForecastDescriptor,DeleteForecastRequestParameters, IDeleteForecastRequest>, IDeleteForecastRequest
{
/// <summary>/_xpack/ml/anomaly_detectors/{job_id}/_forecast/{forecast_id}</summary>
///<param name="job_id"> this parameter is required</param>
///<param name="forecast_id"> this parameter is required</param>
public DeleteForecastDescriptor(Id job_id, ForecastIds forecast_id) : base(r=>r.Required("job_id", job_id).Required("forecast_id", forecast_id)){}
// values part of the url path
Id IDeleteForecastRequest.JobId => Self.RouteValues.Get<Id>("job_id");
ForecastIds IDeleteForecastRequest.ForecastId => Self.RouteValues.Get<ForecastIds>("forecast_id");

// Request parameters

///<summary>Whether to ignore if `_all` matches no forecasts</summary>
public DeleteForecastDescriptor AllowNoForecasts(bool? allowNoForecasts = true) => Qs("allow_no_forecasts", allowNoForecasts);
///<summary>Controls the time to wait until the forecast(s) are deleted. Default to 30 seconds</summary>
public DeleteForecastDescriptor Timeout(Time timeout) => Qs("timeout", timeout);
}
///<summary>descriptor for XpackMlDeleteJob <pre>http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-job.html</pre></summary>
public partial class DeleteJobDescriptor : RequestDescriptorBase<DeleteJobDescriptor,DeleteJobRequestParameters, IDeleteJobRequest>, IDeleteJobRequest
{
Expand Down
22 changes: 22 additions & 0 deletions src/Nest/_Generated/_LowLevelDispatch.generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3506,6 +3506,28 @@ internal Task<TResponse> XpackMlDeleteExpiredDataDispatchAsync<TResponse>(IReque
throw InvalidDispatch("XpackMlDeleteExpiredData", p, new [] { DELETE }, "/_xpack/ml/_delete_expired_data");
}

internal TResponse XpackMlDeleteForecastDispatch<TResponse>(IRequest<DeleteForecastRequestParameters> p) where TResponse : class, IElasticsearchResponse, new()
{
switch(p.HttpMethod)
{
case DELETE:
if (AllSetNoFallback(p.RouteValues.JobId, p.RouteValues.ForecastId)) return _lowLevel.XpackMlDeleteForecast<TResponse>(p.RouteValues.JobId,p.RouteValues.ForecastId,p.RequestParameters);
break;
}
throw InvalidDispatch("XpackMlDeleteForecast", p, new [] { DELETE }, "/_xpack/ml/anomaly_detectors/{job_id}/_forecast/{forecast_id}");
}

internal Task<TResponse> XpackMlDeleteForecastDispatchAsync<TResponse>(IRequest<DeleteForecastRequestParameters> p, CancellationToken ct) where TResponse : class, IElasticsearchResponse, new()
{
switch(p.HttpMethod)
{
case DELETE:
if (AllSetNoFallback(p.RouteValues.JobId, p.RouteValues.ForecastId)) return _lowLevel.XpackMlDeleteForecastAsync<TResponse>(p.RouteValues.JobId,p.RouteValues.ForecastId,p.RequestParameters,ct);
break;
}
throw InvalidDispatch("XpackMlDeleteForecast", p, new [] { DELETE }, "/_xpack/ml/anomaly_detectors/{job_id}/_forecast/{forecast_id}");
}

internal TResponse XpackMlDeleteJobDispatch<TResponse>(IRequest<DeleteJobRequestParameters> p) where TResponse : class, IElasticsearchResponse, new()
{
switch(p.HttpMethod)
Expand Down
24 changes: 24 additions & 0 deletions src/Nest/_Generated/_Requests.generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1893,6 +1893,30 @@ public partial class DeleteExpiredDataRequest : PlainRequestBase<DeleteExpiredDa
// Request parameters
}
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public partial interface IDeleteForecastRequest : IRequest<DeleteForecastRequestParameters>
{
Id JobId { get; }
ForecastIds ForecastId { get; }
}
///<summary>Request parameters for XpackMlDeleteForecast <pre>http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-forecast.html</pre></summary>
public partial class DeleteForecastRequest : PlainRequestBase<DeleteForecastRequestParameters>, IDeleteForecastRequest
{
protected IDeleteForecastRequest Self => this;
///<summary>/_xpack/ml/anomaly_detectors/{job_id}/_forecast/{forecast_id}</summary>
///<param name="job_id">this parameter is required</param>
///<param name="forecast_id">this parameter is required</param>
public DeleteForecastRequest(Id job_id, ForecastIds forecast_id) : base(r=>r.Required("job_id", job_id).Required("forecast_id", forecast_id)){}
// values part of the url path
Id IDeleteForecastRequest.JobId => Self.RouteValues.Get<Id>("job_id");
ForecastIds IDeleteForecastRequest.ForecastId => Self.RouteValues.Get<ForecastIds>("forecast_id");

// Request parameters
///<summary>Whether to ignore if `_all` matches no forecasts</summary>
public bool? AllowNoForecasts { get => Q<bool?>("allow_no_forecasts"); set => Q("allow_no_forecasts", value); }
///<summary>Controls the time to wait until the forecast(s) are deleted. Default to 30 seconds</summary>
public Time Timeout { get => Q<Time>("timeout"); set => Q("timeout", value); }
}
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public partial interface IDeleteIndexRequest : IRequest<DeleteIndexRequestParameters>
{
Indices Index { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ public class ImplicitConversionTests
{
private static T Implicit<T>(T i) => i;

[U] public void ForecastIds()
{
Implicit<ForecastIds>(null).Should().BeNull();
Implicit<ForecastIds>("").Should().BeNull();
Implicit<ForecastIds>(" ").Should().BeNull();
Implicit<ForecastIds>(",, ,,").Should().BeNull();
Implicit<ForecastIds>(new string[] { }).Should().BeNull();
Implicit<ForecastIds>(new string[] { null, null }).Should().BeNull();
}

[U] public void ActionIds()
{
Implicit<ActionIds>(null).Should().BeNull();
Expand Down
28 changes: 28 additions & 0 deletions src/Tests/Tests/CommonOptions/ForecastIdTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Collections.Generic;
using Elastic.Xunit.XunitPlumbing;
using FluentAssertions;
using Nest;

namespace Tests.CommonOptions
{
public class ForecastIdTests
{
[U] public void Equal()
{
var forecastIds1 = new ForecastIds("1,2,3");
var forecastIds2 = new ForecastIds(new [] { "3", "2", "1" });

forecastIds1.Should().Be(forecastIds2);
forecastIds1.GetHashCode().Should().Be(forecastIds2.GetHashCode());
}

[U] public void NotEqual()
{
var forecastIds1 = new ForecastIds("1,2,3,3");
var forecastIds2 = new ForecastIds(new [] { "3", "2", "1" });

forecastIds1.Should().NotBe(forecastIds2);
forecastIds1.GetHashCode().Should().NotBe(forecastIds2.GetHashCode());
}
}
}

0 comments on commit e1a2a13

Please sign in to comment.