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

Fix #3320 Add Painless script execute API #3370

Merged
merged 4 commits into from
Aug 20, 2018
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
2 changes: 0 additions & 2 deletions src/CodeGeneration/ApiGenerator/ApiGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1751,6 +1751,11 @@ public partial class RenderSearchTemplateRequestParameters : RequestParameters<R
{
public override HttpMethod DefaultHttpMethod => HttpMethod.POST;
}
///<summary>Request options for ScriptsPainlessExecute<pre>https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html</pre></summary>
public partial class ExecutePainlessScriptRequestParameters : RequestParameters<ExecutePainlessScriptRequestParameters>
{
public override HttpMethod DefaultHttpMethod => HttpMethod.POST;
}
///<summary>Request options for Scroll<pre>http://www.elastic.co/guide/en/elasticsearch/reference/master/search-request-scroll.html</pre></summary>
public partial class ScrollRequestParameters : RequestParameters<ScrollRequestParameters>
{
Expand Down
18 changes: 18 additions & 0 deletions src/Elasticsearch.Net/ElasticLowLevelClient.Generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2416,6 +2416,24 @@ public TResponse RenderSearchTemplate<TResponse>(string id, PostData body, Rende
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
public Task<TResponse> RenderSearchTemplateAsync<TResponse>(string id, PostData body, RenderSearchTemplateRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken))
where TResponse : class, IElasticsearchResponse, new() => this.DoRequestAsync<TResponse>(POST, Url($"_render/template/{id.NotNull("id")}"), ctx, body, _params(requestParameters));
///<summary>GET on /_scripts/painless/_execute <para>https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html</para></summary>
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
public TResponse ScriptsPainlessExecuteGet<TResponse>(ExecutePainlessScriptRequestParameters requestParameters = null)
where TResponse : class, IElasticsearchResponse, new() => this.DoRequest<TResponse>(GET, Url($"_scripts/painless/_execute"), null, _params(requestParameters));
///<summary>GET on /_scripts/painless/_execute <para>https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html</para></summary>
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
public Task<TResponse> ScriptsPainlessExecuteGetAsync<TResponse>(ExecutePainlessScriptRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken))
where TResponse : class, IElasticsearchResponse, new() => this.DoRequestAsync<TResponse>(GET, Url($"_scripts/painless/_execute"), ctx, null, _params(requestParameters));
///<summary>POST on /_scripts/painless/_execute <para>https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html</para></summary>
///<param name="body">The script to execute</param>
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
public TResponse ScriptsPainlessExecute<TResponse>(PostData body, ExecutePainlessScriptRequestParameters requestParameters = null)
where TResponse : class, IElasticsearchResponse, new() => this.DoRequest<TResponse>(POST, Url($"_scripts/painless/_execute"), body, _params(requestParameters));
///<summary>POST on /_scripts/painless/_execute <para>https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html</para></summary>
///<param name="body">The script to execute</param>
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
public Task<TResponse> ScriptsPainlessExecuteAsync<TResponse>(PostData body, ExecutePainlessScriptRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken))
where TResponse : class, IElasticsearchResponse, new() => this.DoRequestAsync<TResponse>(POST, Url($"_scripts/painless/_execute"), ctx, body, _params(requestParameters));
///<summary>GET on /_search/scroll <para>http://www.elastic.co/guide/en/elasticsearch/reference/master/search-request-scroll.html</para></summary>
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
public TResponse ScrollGet<TResponse>(ScrollRequestParameters requestParameters = null)
Expand Down
14 changes: 14 additions & 0 deletions src/Elasticsearch.Net/IElasticLowLevelClient.Generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1956,6 +1956,20 @@ public partial interface IElasticLowLevelClient
///<param name="body">The search definition template and its params</param>
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
Task<TResponse> RenderSearchTemplateAsync<TResponse>(string id, PostData body, RenderSearchTemplateRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) where TResponse : class, IElasticsearchResponse, new();
///<summary>GET on /_scripts/painless/_execute <para>https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html</para></summary>
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
TResponse ScriptsPainlessExecuteGet<TResponse>(ExecutePainlessScriptRequestParameters requestParameters = null) where TResponse : class, IElasticsearchResponse, new();
///<summary>GET on /_scripts/painless/_execute <para>https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html</para></summary>
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
Task<TResponse> ScriptsPainlessExecuteGetAsync<TResponse>(ExecutePainlessScriptRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) where TResponse : class, IElasticsearchResponse, new();
///<summary>POST on /_scripts/painless/_execute <para>https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html</para></summary>
///<param name="body">The script to execute</param>
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
TResponse ScriptsPainlessExecute<TResponse>(PostData body, ExecutePainlessScriptRequestParameters requestParameters = null) where TResponse : class, IElasticsearchResponse, new();
///<summary>POST on /_scripts/painless/_execute <para>https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html</para></summary>
///<param name="body">The script to execute</param>
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
Task<TResponse> ScriptsPainlessExecuteAsync<TResponse>(PostData body, ExecutePainlessScriptRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) where TResponse : class, IElasticsearchResponse, new();
///<summary>GET on /_search/scroll <para>http://www.elastic.co/guide/en/elasticsearch/reference/master/search-request-scroll.html</para></summary>
///<param name="requestParameters">A func that allows you to describe the querystring parameters &amp; request specific connection settings.</param>
TResponse ScrollGet<TResponse>(ScrollRequestParameters requestParameters = null) where TResponse : class, IElasticsearchResponse, new();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;
using System.Threading.Tasks;
using Elasticsearch.Net;
using System.Threading;

namespace Nest
{
public partial interface IElasticClient
{
/// <summary>
/// Executes an arbitrary Painless script and returns a result.
/// Useful for testing the syntactical correctness of Painless scripts
/// </summary>
IExecutePainlessScriptResponse<TResult> ExecutePainlessScript<TResult>(Func<ExecutePainlessScriptDescriptor, IExecutePainlessScriptRequest> selector);

/// <inheritdoc cref="ExecutePainlessScript{TResult}(System.Func{Nest.ExecutePainlessScriptDescriptor,Nest.IExecutePainlessScriptRequest})"/>
IExecutePainlessScriptResponse<TResult> ExecutePainlessScript<TResult>(IExecutePainlessScriptRequest request);

/// <inheritdoc cref="ExecutePainlessScript{TResult}(System.Func{Nest.ExecutePainlessScriptDescriptor,Nest.IExecutePainlessScriptRequest})"/>
Task<IExecutePainlessScriptResponse<TResult>> ExecutePainlessScriptAsync<TResult>(Func<ExecutePainlessScriptDescriptor, IExecutePainlessScriptRequest> selector,
CancellationToken cancellationToken = default(CancellationToken));

/// <inheritdoc cref="ExecutePainlessScript{TResult}(System.Func{Nest.ExecutePainlessScriptDescriptor,Nest.IExecutePainlessScriptRequest})"/>
Task<IExecutePainlessScriptResponse<TResult>> ExecutePainlessScriptAsync<TResult>(IExecutePainlessScriptRequest request, CancellationToken cancellationToken = default(CancellationToken));

}

public partial class ElasticClient
{
/// <inheritdoc />
public IExecutePainlessScriptResponse<TResult> ExecutePainlessScript<TResult>(Func<ExecutePainlessScriptDescriptor, IExecutePainlessScriptRequest> selector) =>
this.ExecutePainlessScript<TResult>(selector?.Invoke(new ExecutePainlessScriptDescriptor()));

/// <inheritdoc />
public IExecutePainlessScriptResponse<TResult> ExecutePainlessScript<TResult>(IExecutePainlessScriptRequest request) =>
this.Dispatcher.Dispatch<IExecutePainlessScriptRequest, ExecutePainlessScriptRequestParameters, ExecutePainlessScriptResponse<TResult>>(
request,
this.LowLevelDispatch.ScriptsPainlessExecuteDispatch<ExecutePainlessScriptResponse<TResult>>
);

/// <inheritdoc />
public Task<IExecutePainlessScriptResponse<TResult>> ExecutePainlessScriptAsync<TResult>(Func<ExecutePainlessScriptDescriptor, IExecutePainlessScriptRequest> selector,
CancellationToken cancellationToken = default(CancellationToken)) =>
this.ExecutePainlessScriptAsync<TResult>(selector?.Invoke(new ExecutePainlessScriptDescriptor()), cancellationToken);

/// <inheritdoc />
public Task<IExecutePainlessScriptResponse<TResult>> ExecutePainlessScriptAsync<TResult>(IExecutePainlessScriptRequest request, CancellationToken cancellationToken = default(CancellationToken)) =>
this.Dispatcher.DispatchAsync<IExecutePainlessScriptRequest, ExecutePainlessScriptRequestParameters, ExecutePainlessScriptResponse<TResult>, IExecutePainlessScriptResponse<TResult>>(
request,
cancellationToken,
this.LowLevelDispatch.ScriptsPainlessExecuteDispatchAsync<ExecutePainlessScriptResponse<TResult>>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using Newtonsoft.Json;

namespace Nest
{
public partial interface IExecutePainlessScriptRequest
{
[JsonProperty("script")]
IInlineScript Script { get; set; }
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing Context?

https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-execute-api.html

Can be added later though, as there is only one context at this point

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind, just seen the commit message 😄


public partial class ExecutePainlessScriptRequest
{
public IInlineScript Script { get; set; }
}

[DescriptorFor("ScriptsPainlessExecute")]
public partial class ExecutePainlessScriptDescriptor
{
IInlineScript IExecutePainlessScriptRequest.Script { get; set; }

public ExecutePainlessScriptDescriptor Script(Func<InlineScriptDescriptor, IInlineScript> selector) =>
Assign(a => a.Script = selector?.Invoke(new InlineScriptDescriptor()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Newtonsoft.Json;

namespace Nest
{
public interface IExecutePainlessScriptResponse<TResult> : IResponse
{
[JsonProperty("result")]
TResult Result { get; }
}

public class ExecutePainlessScriptResponse<TResult> : ResponseBase, IExecutePainlessScriptResponse<TResult>
{
public TResult Result { get; set; }
}
}
8 changes: 8 additions & 0 deletions src/Nest/_Generated/_Descriptors.generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3124,6 +3124,14 @@ public RenderSearchTemplateDescriptor() : base(){}

// Request parameters

}
///<summary>descriptor for ScriptsPainlessExecute <pre>https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html</pre></summary>
public partial class ExecutePainlessScriptDescriptor : RequestDescriptorBase<ExecutePainlessScriptDescriptor,ExecutePainlessScriptRequestParameters, IExecutePainlessScriptRequest>, IExecutePainlessScriptRequest
{
// values part of the url path

// Request parameters

}
///<summary>descriptor for Scroll <pre>http://www.elastic.co/guide/en/elasticsearch/reference/master/search-request-scroll.html</pre></summary>
public partial class ScrollDescriptor<T> : RequestDescriptorBase<ScrollDescriptor<T>,ScrollRequestParameters, IScrollRequest>, IScrollRequest
Expand Down
24 changes: 24 additions & 0 deletions src/Nest/_Generated/_LowLevelDispatch.generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2408,6 +2408,30 @@ internal partial class LowLevelDispatch
throw InvalidDispatch("RenderSearchTemplate", p, new [] { GET, POST }, "/_render/template", "/_render/template/{id}");
}

internal TResponse ScriptsPainlessExecuteDispatch<TResponse>(IRequest<ExecutePainlessScriptRequestParameters> p,SerializableData<IExecutePainlessScriptRequest> body) where TResponse : class, IElasticsearchResponse, new()
{
switch(p.HttpMethod)
{
case GET:
return _lowLevel.ScriptsPainlessExecuteGet<TResponse>(p.RequestParameters);
case POST:
return _lowLevel.ScriptsPainlessExecute<TResponse>(body,p.RequestParameters);
}
throw InvalidDispatch("ScriptsPainlessExecute", p, new [] { GET, POST }, "/_scripts/painless/_execute");
}

internal Task<TResponse> ScriptsPainlessExecuteDispatchAsync<TResponse>(IRequest<ExecutePainlessScriptRequestParameters> p,SerializableData<IExecutePainlessScriptRequest> body, CancellationToken ct) where TResponse : class, IElasticsearchResponse, new()
{
switch(p.HttpMethod)
{
case GET:
return _lowLevel.ScriptsPainlessExecuteGetAsync<TResponse>(p.RequestParameters,ct);
case POST:
return _lowLevel.ScriptsPainlessExecuteAsync<TResponse>(body,p.RequestParameters,ct);
}
throw InvalidDispatch("ScriptsPainlessExecute", p, new [] { GET, POST }, "/_scripts/painless/_execute");
}

internal TResponse ScrollDispatch<TResponse>(IRequest<ScrollRequestParameters> p,SerializableData<IScrollRequest> body) where TResponse : class, IElasticsearchResponse, new()
{
switch(p.HttpMethod)
Expand Down
12 changes: 12 additions & 0 deletions src/Nest/_Generated/_Requests.generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2246,6 +2246,18 @@ public EnableUserRequest(Name username) : base(r=>r.Optional("username", usernam
public Refresh? Refresh { get => Q<Refresh?>("refresh"); set => Q("refresh", value); }
}
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public partial interface IExecutePainlessScriptRequest : IRequest<ExecutePainlessScriptRequestParameters>
{
}
///<summary>Request parameters for ScriptsPainlessExecute <pre>https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html</pre></summary>
public partial class ExecutePainlessScriptRequest : PlainRequestBase<ExecutePainlessScriptRequestParameters>, IExecutePainlessScriptRequest
{
protected IExecutePainlessScriptRequest Self => this;
// values part of the url path

// Request parameters
}
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public partial interface IExecuteWatchRequest : IRequest<ExecuteWatchRequestParameters>
{
Id Id { get; }
Expand Down
Original file line number Diff line number Diff line change
@@ -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<ReadOnlyCluster, IExecutePainlessScriptResponse<string>, 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<string>(f),
fluentAsync: (client, f) => client.ExecutePainlessScriptAsync<string>(f),
request: (client, r) => client.ExecutePainlessScript<string>(r),
requestAsync: (client, r) => client.ExecutePainlessScriptAsync<string>(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<ExecutePainlessScriptDescriptor, IExecutePainlessScriptRequest> 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<string, object>
{
{ "count", 100.0 },
{ "total", 1000.0 },
}
}
};

protected override void ExpectResponse(IExecutePainlessScriptResponse<string> response)
{
response.ShouldBeValid();
response.Result.Should().NotBeNullOrWhiteSpace();
}
}
}
Original file line number Diff line number Diff line change
@@ -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<string>(f => f.Script(s => s.Source(painless))))
.Request(c => c.ExecutePainlessScript<string>(request))
.FluentAsync(c => c.ExecutePainlessScriptAsync<string>(f => f.Script(s => s.Source(painless))))
.RequestAsync(c => c.ExecutePainlessScriptAsync<string>(request))
;
}
}
}