diff --git a/src/CodeGeneration/ApiGenerator/ApiGenerator.cs b/src/CodeGeneration/ApiGenerator/ApiGenerator.cs index 44e0842d4ba..0a2ff7d1349 100644 --- a/src/CodeGeneration/ApiGenerator/ApiGenerator.cs +++ b/src/CodeGeneration/ApiGenerator/ApiGenerator.cs @@ -84,8 +84,6 @@ public static void Generate(string downloadBranch, params string[] folders) "xpack.sql.query.json", "xpack.sql.translate.json", "xpack.ssl.certificates.json", - - "scripts_painless_execute.json", }; private static RestApiSpec CreateRestApiSpecModel(string downloadBranch, string[] folders) diff --git a/src/Elasticsearch.Net/Domain/RequestParameters/RequestParameters.Generated.cs b/src/Elasticsearch.Net/Domain/RequestParameters/RequestParameters.Generated.cs index cde78595e10..9efe394d6d8 100644 --- a/src/Elasticsearch.Net/Domain/RequestParameters/RequestParameters.Generated.cs +++ b/src/Elasticsearch.Net/Domain/RequestParameters/RequestParameters.Generated.cs @@ -1751,6 +1751,11 @@ public partial class RenderSearchTemplateRequestParameters : RequestParameters HttpMethod.POST; } + ///Request options for ScriptsPainlessExecute
https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html
+ public partial class ExecutePainlessScriptRequestParameters : RequestParameters + { + public override HttpMethod DefaultHttpMethod => HttpMethod.POST; + } ///Request options for Scroll
http://www.elastic.co/guide/en/elasticsearch/reference/master/search-request-scroll.html
public partial class ScrollRequestParameters : RequestParameters { diff --git a/src/Elasticsearch.Net/ElasticLowLevelClient.Generated.cs b/src/Elasticsearch.Net/ElasticLowLevelClient.Generated.cs index 4aaa7eb7f6d..a7cbbdc61d2 100644 --- a/src/Elasticsearch.Net/ElasticLowLevelClient.Generated.cs +++ b/src/Elasticsearch.Net/ElasticLowLevelClient.Generated.cs @@ -2416,6 +2416,24 @@ public TResponse RenderSearchTemplate(string id, PostData body, Rende ///A func that allows you to describe the querystring parameters & request specific connection settings. public Task RenderSearchTemplateAsync(string id, PostData body, RenderSearchTemplateRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) where TResponse : class, IElasticsearchResponse, new() => this.DoRequestAsync(POST, Url($"_render/template/{id.NotNull("id")}"), ctx, body, _params(requestParameters)); + ///GET on /_scripts/painless/_execute https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html + ///A func that allows you to describe the querystring parameters & request specific connection settings. + public TResponse ScriptsPainlessExecuteGet(ExecutePainlessScriptRequestParameters requestParameters = null) + where TResponse : class, IElasticsearchResponse, new() => this.DoRequest(GET, Url($"_scripts/painless/_execute"), null, _params(requestParameters)); + ///GET on /_scripts/painless/_execute https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html + ///A func that allows you to describe the querystring parameters & request specific connection settings. + public Task ScriptsPainlessExecuteGetAsync(ExecutePainlessScriptRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) + where TResponse : class, IElasticsearchResponse, new() => this.DoRequestAsync(GET, Url($"_scripts/painless/_execute"), ctx, null, _params(requestParameters)); + ///POST on /_scripts/painless/_execute https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html + ///The script to execute + ///A func that allows you to describe the querystring parameters & request specific connection settings. + public TResponse ScriptsPainlessExecute(PostData body, ExecutePainlessScriptRequestParameters requestParameters = null) + where TResponse : class, IElasticsearchResponse, new() => this.DoRequest(POST, Url($"_scripts/painless/_execute"), body, _params(requestParameters)); + ///POST on /_scripts/painless/_execute https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html + ///The script to execute + ///A func that allows you to describe the querystring parameters & request specific connection settings. + public Task ScriptsPainlessExecuteAsync(PostData body, ExecutePainlessScriptRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) + where TResponse : class, IElasticsearchResponse, new() => this.DoRequestAsync(POST, Url($"_scripts/painless/_execute"), ctx, body, _params(requestParameters)); ///GET on /_search/scroll http://www.elastic.co/guide/en/elasticsearch/reference/master/search-request-scroll.html ///A func that allows you to describe the querystring parameters & request specific connection settings. public TResponse ScrollGet(ScrollRequestParameters requestParameters = null) diff --git a/src/Elasticsearch.Net/IElasticLowLevelClient.Generated.cs b/src/Elasticsearch.Net/IElasticLowLevelClient.Generated.cs index 354ab3df777..577288ec335 100644 --- a/src/Elasticsearch.Net/IElasticLowLevelClient.Generated.cs +++ b/src/Elasticsearch.Net/IElasticLowLevelClient.Generated.cs @@ -1956,6 +1956,20 @@ public partial interface IElasticLowLevelClient ///The search definition template and its params ///A func that allows you to describe the querystring parameters & request specific connection settings. Task RenderSearchTemplateAsync(string id, PostData body, RenderSearchTemplateRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) where TResponse : class, IElasticsearchResponse, new(); + ///GET on /_scripts/painless/_execute https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html + ///A func that allows you to describe the querystring parameters & request specific connection settings. + TResponse ScriptsPainlessExecuteGet(ExecutePainlessScriptRequestParameters requestParameters = null) where TResponse : class, IElasticsearchResponse, new(); + ///GET on /_scripts/painless/_execute https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html + ///A func that allows you to describe the querystring parameters & request specific connection settings. + Task ScriptsPainlessExecuteGetAsync(ExecutePainlessScriptRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) where TResponse : class, IElasticsearchResponse, new(); + ///POST on /_scripts/painless/_execute https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html + ///The script to execute + ///A func that allows you to describe the querystring parameters & request specific connection settings. + TResponse ScriptsPainlessExecute(PostData body, ExecutePainlessScriptRequestParameters requestParameters = null) where TResponse : class, IElasticsearchResponse, new(); + ///POST on /_scripts/painless/_execute https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html + ///The script to execute + ///A func that allows you to describe the querystring parameters & request specific connection settings. + Task ScriptsPainlessExecuteAsync(PostData body, ExecutePainlessScriptRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) where TResponse : class, IElasticsearchResponse, new(); ///GET on /_search/scroll http://www.elastic.co/guide/en/elasticsearch/reference/master/search-request-scroll.html ///A func that allows you to describe the querystring parameters & request specific connection settings. TResponse ScrollGet(ScrollRequestParameters requestParameters = null) where TResponse : class, IElasticsearchResponse, new(); diff --git a/src/Nest/Modules/Scripting/ExecutePainlessScript/ElasticClient-ExecutePainlessScript.cs b/src/Nest/Modules/Scripting/ExecutePainlessScript/ElasticClient-ExecutePainlessScript.cs new file mode 100644 index 00000000000..f37d57783d1 --- /dev/null +++ b/src/Nest/Modules/Scripting/ExecutePainlessScript/ElasticClient-ExecutePainlessScript.cs @@ -0,0 +1,54 @@ +using System; +using System.Threading.Tasks; +using Elasticsearch.Net; +using System.Threading; + +namespace Nest +{ + public partial interface IElasticClient + { + /// + /// Executes an arbitrary Painless script and returns a result. + /// Useful for testing the syntactical correctness of Painless scripts + /// + IExecutePainlessScriptResponse ExecutePainlessScript(Func selector); + + /// + IExecutePainlessScriptResponse ExecutePainlessScript(IExecutePainlessScriptRequest request); + + /// + Task> ExecutePainlessScriptAsync(Func selector, + CancellationToken cancellationToken = default(CancellationToken)); + + /// + Task> ExecutePainlessScriptAsync(IExecutePainlessScriptRequest request, CancellationToken cancellationToken = default(CancellationToken)); + + } + + public partial class ElasticClient + { + /// + public IExecutePainlessScriptResponse ExecutePainlessScript(Func selector) => + this.ExecutePainlessScript(selector?.Invoke(new ExecutePainlessScriptDescriptor())); + + /// + public IExecutePainlessScriptResponse ExecutePainlessScript(IExecutePainlessScriptRequest request) => + this.Dispatcher.Dispatch>( + request, + this.LowLevelDispatch.ScriptsPainlessExecuteDispatch> + ); + + /// + public Task> ExecutePainlessScriptAsync(Func selector, + CancellationToken cancellationToken = default(CancellationToken)) => + this.ExecutePainlessScriptAsync(selector?.Invoke(new ExecutePainlessScriptDescriptor()), cancellationToken); + + /// + public Task> ExecutePainlessScriptAsync(IExecutePainlessScriptRequest request, CancellationToken cancellationToken = default(CancellationToken)) => + this.Dispatcher.DispatchAsync, IExecutePainlessScriptResponse>( + request, + cancellationToken, + this.LowLevelDispatch.ScriptsPainlessExecuteDispatchAsync> + ); + } +} diff --git a/src/Nest/Modules/Scripting/ExecutePainlessScript/ExecutePainlessScriptRequest.cs b/src/Nest/Modules/Scripting/ExecutePainlessScript/ExecutePainlessScriptRequest.cs new file mode 100644 index 00000000000..c9bf286cdb6 --- /dev/null +++ b/src/Nest/Modules/Scripting/ExecutePainlessScript/ExecutePainlessScriptRequest.cs @@ -0,0 +1,25 @@ +using System; +using Newtonsoft.Json; + +namespace Nest +{ + public partial interface IExecutePainlessScriptRequest + { + [JsonProperty("script")] + IInlineScript Script { get; set; } + } + + public partial class ExecutePainlessScriptRequest + { + public IInlineScript Script { get; set; } + } + + [DescriptorFor("ScriptsPainlessExecute")] + public partial class ExecutePainlessScriptDescriptor + { + IInlineScript IExecutePainlessScriptRequest.Script { get; set; } + + public ExecutePainlessScriptDescriptor Script(Func selector) => + Assign(a => a.Script = selector?.Invoke(new InlineScriptDescriptor())); + } +} diff --git a/src/Nest/Modules/Scripting/ExecutePainlessScript/ExecutePainlessScriptResponse.cs b/src/Nest/Modules/Scripting/ExecutePainlessScript/ExecutePainlessScriptResponse.cs new file mode 100644 index 00000000000..d14936015d0 --- /dev/null +++ b/src/Nest/Modules/Scripting/ExecutePainlessScript/ExecutePainlessScriptResponse.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; + +namespace Nest +{ + public interface IExecutePainlessScriptResponse : IResponse + { + [JsonProperty("result")] + TResult Result { get; } + } + + public class ExecutePainlessScriptResponse : ResponseBase, IExecutePainlessScriptResponse + { + public TResult Result { get; set; } + } +} diff --git a/src/Nest/_Generated/_Descriptors.generated.cs b/src/Nest/_Generated/_Descriptors.generated.cs index 509aa2e9ee0..ba837c6bf11 100644 --- a/src/Nest/_Generated/_Descriptors.generated.cs +++ b/src/Nest/_Generated/_Descriptors.generated.cs @@ -3124,6 +3124,14 @@ public RenderSearchTemplateDescriptor() : base(){} // Request parameters + } + ///descriptor for ScriptsPainlessExecute
https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html
+ public partial class ExecutePainlessScriptDescriptor : RequestDescriptorBase, IExecutePainlessScriptRequest + { + // values part of the url path + + // Request parameters + } ///descriptor for Scroll
http://www.elastic.co/guide/en/elasticsearch/reference/master/search-request-scroll.html
public partial class ScrollDescriptor : RequestDescriptorBase,ScrollRequestParameters, IScrollRequest>, IScrollRequest diff --git a/src/Nest/_Generated/_LowLevelDispatch.generated.cs b/src/Nest/_Generated/_LowLevelDispatch.generated.cs index 7085ce45018..609af3e7ac8 100644 --- a/src/Nest/_Generated/_LowLevelDispatch.generated.cs +++ b/src/Nest/_Generated/_LowLevelDispatch.generated.cs @@ -2408,6 +2408,30 @@ internal partial class LowLevelDispatch throw InvalidDispatch("RenderSearchTemplate", p, new [] { GET, POST }, "/_render/template", "/_render/template/{id}"); } + internal TResponse ScriptsPainlessExecuteDispatch(IRequest p,SerializableData body) where TResponse : class, IElasticsearchResponse, new() + { + switch(p.HttpMethod) + { + case GET: + return _lowLevel.ScriptsPainlessExecuteGet(p.RequestParameters); + case POST: + return _lowLevel.ScriptsPainlessExecute(body,p.RequestParameters); + } + throw InvalidDispatch("ScriptsPainlessExecute", p, new [] { GET, POST }, "/_scripts/painless/_execute"); + } + + internal Task ScriptsPainlessExecuteDispatchAsync(IRequest p,SerializableData body, CancellationToken ct) where TResponse : class, IElasticsearchResponse, new() + { + switch(p.HttpMethod) + { + case GET: + return _lowLevel.ScriptsPainlessExecuteGetAsync(p.RequestParameters,ct); + case POST: + return _lowLevel.ScriptsPainlessExecuteAsync(body,p.RequestParameters,ct); + } + throw InvalidDispatch("ScriptsPainlessExecute", p, new [] { GET, POST }, "/_scripts/painless/_execute"); + } + internal TResponse ScrollDispatch(IRequest p,SerializableData body) where TResponse : class, IElasticsearchResponse, new() { switch(p.HttpMethod) diff --git a/src/Nest/_Generated/_Requests.generated.cs b/src/Nest/_Generated/_Requests.generated.cs index dd491cfdd77..9f8795da7f8 100644 --- a/src/Nest/_Generated/_Requests.generated.cs +++ b/src/Nest/_Generated/_Requests.generated.cs @@ -2246,6 +2246,18 @@ public EnableUserRequest(Name username) : base(r=>r.Optional("username", usernam public Refresh? Refresh { get => Q("refresh"); set => Q("refresh", value); } } [JsonObject(MemberSerialization = MemberSerialization.OptIn)] + public partial interface IExecutePainlessScriptRequest : IRequest + { + } + ///Request parameters for ScriptsPainlessExecute
https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html
+ public partial class ExecutePainlessScriptRequest : PlainRequestBase, IExecutePainlessScriptRequest + { + protected IExecutePainlessScriptRequest Self => this; + // values part of the url path + + // Request parameters + } + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public partial interface IExecuteWatchRequest : IRequest { Id Id { get; } diff --git a/src/Tests/Tests/Modules/Scripting/ExecutePainlessScript/ExecutePainlessScriptApiTests.cs b/src/Tests/Tests/Modules/Scripting/ExecutePainlessScript/ExecutePainlessScriptApiTests.cs new file mode 100644 index 00000000000..31b4447e729 --- /dev/null +++ b/src/Tests/Tests/Modules/Scripting/ExecutePainlessScript/ExecutePainlessScriptApiTests.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Elastic.Xunit.XunitPlumbing; +using Elasticsearch.Net; +using FluentAssertions; +using Nest; +using Tests.Core.Extensions; +using Tests.Core.ManagedElasticsearch.Clusters; +using Tests.Framework; +using Tests.Framework.Integration; +using Tests.Framework.ManagedElasticsearch.Clusters; +using Xunit; + +namespace Tests.Modules.Scripting.ExecutePainlessScript +{ + [SkipVersion("<6.3.0", "this API was introduced in 6.3.0")] + public class ExecutePainlessScriptApiTests + : ApiIntegrationTestBase, IExecutePainlessScriptRequest, ExecutePainlessScriptDescriptor, ExecutePainlessScriptRequest> + { + public ExecutePainlessScriptApiTests(ReadOnlyCluster cluster, EndpointUsage usage) : base(cluster, usage) { } + + private static readonly string _painlessScript = "params.count / params.total"; + + protected override LazyResponses ClientUsage() => Calls( + fluent: (client, f) => client.ExecutePainlessScript(f), + fluentAsync: (client, f) => client.ExecutePainlessScriptAsync(f), + request: (client, r) => client.ExecutePainlessScript(r), + requestAsync: (client, r) => client.ExecutePainlessScriptAsync(r) + ); + + protected override HttpMethod HttpMethod => HttpMethod.POST; + protected override string UrlPath => "/_scripts/painless/_execute"; + protected override int ExpectStatusCode => 200; + protected override bool ExpectIsValid => true; + + protected override bool SupportsDeserialization => false; + + protected override object ExpectJson => new + { + script = new + { + source = _painlessScript, + @params = new { count = 100.0, total = 1000.0 } + }, + }; + + protected override Func Fluent => d => d + .Script(s=>s + .Source(_painlessScript) + .Params(p => p.Add("count", 100.0).Add("total", 1000.0)) + ); + + protected override ExecutePainlessScriptRequest Initializer => new ExecutePainlessScriptRequest + { + Script = new InlineScript(_painlessScript) + { + Params = new Dictionary + { + { "count", 100.0 }, + { "total", 1000.0 }, + } + } + }; + + protected override void ExpectResponse(IExecutePainlessScriptResponse response) + { + response.ShouldBeValid(); + response.Result.Should().NotBeNullOrWhiteSpace(); + } + } +} diff --git a/src/Tests/Tests/Modules/Scripting/ExecutePainlessScript/ExecutePainlessScriptUrlTests.cs b/src/Tests/Tests/Modules/Scripting/ExecutePainlessScript/ExecutePainlessScriptUrlTests.cs new file mode 100644 index 00000000000..18b364b1356 --- /dev/null +++ b/src/Tests/Tests/Modules/Scripting/ExecutePainlessScript/ExecutePainlessScriptUrlTests.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using Elastic.Xunit.XunitPlumbing; +using Nest; +using Tests.Framework; +using static Tests.Framework.UrlTester; + +namespace Tests.Modules.Scripting.ExecutePainlessScript +{ + public class ExecutePainlessScriptUrlTests + { + [U] public async Task Urls() + { + var painless = "1 + 1"; + var request = new ExecutePainlessScriptRequest + { + Script = new InlineScript(painless) + }; + + await POST("/_scripts/painless/_execute") + .Fluent(c => c.ExecutePainlessScript(f => f.Script(s => s.Source(painless)))) + .Request(c => c.ExecutePainlessScript(request)) + .FluentAsync(c => c.ExecutePainlessScriptAsync(f => f.Script(s => s.Source(painless)))) + .RequestAsync(c => c.ExecutePainlessScriptAsync(request)) + ; + } + } +}