Skip to content

Commit 2147972

Browse files
committed
Merge branch 'feature/2.x-suggest-infer-index' into 2.x
2 parents 1f6d87b + ef76ef5 commit 2147972

File tree

10 files changed

+146
-46
lines changed

10 files changed

+146
-46
lines changed

src/CodeGeneration/ApiGenerator/Domain/CsharpMethod.cs

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -76,24 +76,24 @@ public IEnumerable<Constructor> RequestConstructors()
7676
var m = this.RequestType;
7777
foreach (var url in this.Url.Paths)
7878
{
79-
var cp = this.Url.Parts
79+
var urlRouteParameters = this.Url.Parts
8080
.Where(p => !ApiUrl.BlackListRouteValues.Contains(p.Key))
8181
.Where(p => url.Contains($"{{{p.Value.Name}}}"))
8282
.OrderBy(kv => url.IndexOf($"{{{kv.Value.Name}}}", StringComparison.Ordinal));
83-
var par = string.Join(", ", cp.Select(p => $"{ClrParamType(p.Value.ClrTypeName)} {p.Key}"));
83+
var par = string.Join(", ", urlRouteParameters.Select(p => $"{ClrParamType(p.Value.ClrTypeName)} {p.Key}"));
8484
var routing = string.Empty;
8585

8686
//Routes that take {indices}/{types} and both are optional
8787
//we rather not generate a parameterless constructor and force folks to call Indices.All
88-
if (!cp.Any() && IndicesAndTypes)
88+
if (!urlRouteParameters.Any() && IndicesAndTypes)
8989
{
9090
ParameterlessIndicesTypesConstructor(ctors, m);
9191
continue;
9292
}
9393

94-
if (cp.Any())
94+
if (urlRouteParameters.Any())
9595
{
96-
routing = "r=>r." + string.Join(".", cp
96+
routing = "r=>r." + string.Join(".", urlRouteParameters
9797
.Select(p => new
9898
{
9999
route = p.Key,
@@ -109,17 +109,24 @@ public IEnumerable<Constructor> RequestConstructors()
109109
}
110110

111111
var doc = $@"/// <summary>{url}</summary>";
112-
if (cp.Any())
112+
if (urlRouteParameters.Any())
113113
{
114-
doc += "\r\n" + string.Join("\t\t\r\n", cp.Select(p => $"///<param name=\"{p.Key}\">{(p.Value.Required ? "this parameter is required" : "Optional, accepts null")}</param>"));
114+
doc += "\r\n" + string.Join("\t\t\r\n", urlRouteParameters.Select(p => $"///<param name=\"{p.Key}\">{(p.Value.Required ? "this parameter is required" : "Optional, accepts null")}</param>"));
115115
}
116116
var generated = $"public {m}({par}) : base({routing}){{}}";
117117

118118
// special case SearchRequest<T> to pass the type of T as the type, when only the index is specified.
119-
if (m == "SearchRequest" && cp.Count() == 1 && !string.IsNullOrEmpty(this.RequestTypeGeneric))
119+
if (m == "SearchRequest" && urlRouteParameters.Count() == 1 && !string.IsNullOrEmpty(this.RequestTypeGeneric))
120120
{
121121
var generic = this.RequestTypeGeneric.Replace("<", "").Replace(">", "");
122-
generated = $"public {m}({par}) : this({cp.First().Key}, typeof({generic})){{}}";
122+
generated = $"public {m}({par}) : this({urlRouteParameters.First().Key}, typeof({generic})){{}}";
123+
}
124+
125+
if ((m == "SuggestRequest") && string.IsNullOrEmpty(par) && !string.IsNullOrEmpty(this.RequestTypeGeneric))
126+
{
127+
var generic = this.RequestTypeGeneric.Replace("<", "").Replace(">", "");
128+
doc = AppendToSummary(doc, ". Will infer the index from the generic type");
129+
generated = $"public {m}({par}) : this(typeof({generic})){{}}";
123130
}
124131

125132
var c = new Constructor { Generated = generated, Description = doc };
@@ -159,21 +166,21 @@ public IEnumerable<Constructor> DescriptorConstructors()
159166
var m = this.DescriptorType;
160167
foreach (var url in this.Url.Paths)
161168
{
162-
var cp = this.Url.Parts
169+
var requiredUrlRouteParameters = this.Url.Parts
163170
.Where(p => !ApiUrl.BlackListRouteValues.Contains(p.Key))
164171
.Where(p => p.Value.Required)
165172
.Where(p => url.Contains($"{{{p.Value.Name}}}"))
166173
.OrderBy(kv => url.IndexOf($"{{{kv.Value.Name}}}", StringComparison.Ordinal));
167-
var par = string.Join(", ", cp.Select(p => $"{ClrParamType(p.Value.ClrTypeName)} {p.Key}"));
174+
var par = string.Join(", ", requiredUrlRouteParameters.Select(p => $"{ClrParamType(p.Value.ClrTypeName)} {p.Key}"));
168175
var routing = string.Empty;
169176
//Routes that take {indices}/{types} and both are optional
170-
if (!cp.Any() && IndicesAndTypes)
177+
if (!requiredUrlRouteParameters.Any() && IndicesAndTypes)
171178
{
172179
AddParameterlessIndicesTypesConstructor(ctors, m);
173180
continue;
174181
}
175-
if (cp.Any())
176-
routing = "r=>r." + string.Join(".", cp
182+
if (requiredUrlRouteParameters.Any())
183+
routing = "r=>r." + string.Join(".", requiredUrlRouteParameters
177184
.Select(p => new
178185
{
179186
route = p.Key,
@@ -187,20 +194,28 @@ public IEnumerable<Constructor> DescriptorConstructors()
187194
.Select(p => $"{p.call}(\"{p.route}\", {p.v})")
188195
);
189196
var doc = $@"/// <summary>{url}</summary>";
190-
if (cp.Any())
197+
if (requiredUrlRouteParameters.Any())
191198
{
192-
doc += "\r\n" + string.Join("\t\t\r\n", cp.Select(p => $"///<param name=\"{p.Key}\"> this parameter is required</param>"));
199+
doc += "\r\n" + string.Join("\t\t\r\n", requiredUrlRouteParameters.Select(p => $"///<param name=\"{p.Key}\"> this parameter is required</param>"));
193200
}
194201

195202
var generated = $"public {m}({par}) : base({routing}){{}}";
196203

197204
// Add typeof(T) as the default type when only index specified
198-
if ((m == "UpdateByQueryDescriptor") && cp.Count() == 1 && !string.IsNullOrEmpty(this.RequestTypeGeneric))
205+
if ((m == "UpdateByQueryDescriptor") && requiredUrlRouteParameters.Count() == 1 && !string.IsNullOrEmpty(this.RequestTypeGeneric))
199206
{
200207
var generic = this.RequestTypeGeneric.Replace("<", "").Replace(">", "");
201208
generated = $"public {m}({par}) : base({routing}.Required(\"type\", (Types)typeof({generic}))){{}}";
202209
}
203210

211+
// Add typeof(T) as the default index to use for Suggest
212+
if ((m == "SuggestDescriptor") && !string.IsNullOrEmpty(this.RequestTypeGeneric))
213+
{
214+
var generic = this.RequestTypeGeneric.Replace("<", "").Replace(">", "");
215+
doc = AppendToSummary(doc, ". Will infer the index from the generic type");
216+
generated = $"public {m}({par}) : base(r => r.Required(\"index\", (Indices)typeof({generic}))){{}}";
217+
}
218+
204219
var c = new Constructor { Generated = generated, Description = doc };
205220
ctors.Add(c);
206221
}
@@ -288,6 +303,13 @@ public IEnumerable<FluentRouteSetter> GetFluentRouteSetters()
288303
return setters;
289304
}
290305

306+
private string AppendToSummary(string doc, string toAppend)
307+
{
308+
return Regex.Replace(
309+
doc,
310+
@"^(\/\/\/ <summary>)(.*?)(<\/summary>)(.*)",
311+
"$1$2" + toAppend + "$3$4");
312+
}
291313

292314
private bool IsPartless => this.Url.Parts == null || !this.Url.Parts.Any();
293315
private bool IsScroll => this.Url.Parts.All(p => p.Key == "scroll_id");

src/Nest/Search/Search/ElasticClient-Search.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public partial interface IElasticClient
1111
/// The search API allows to execute a search query and get back search hits that match the query.
1212
/// <para> </para>http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-search.html
1313
/// </summary>
14-
/// <typeparam name="T">The type used to infer the index and typename as well describe the query strongly typed</typeparam>
14+
/// <typeparam name="T">The type used to infer the index and type name as well describe the query strongly typed</typeparam>
1515
/// <param name="selector">A descriptor that describes the parameters for the search operation</param>
1616
ISearchResponse<T> Search<T>(Func<SearchDescriptor<T>, ISearchRequest> selector = null) where T : class;
1717

@@ -29,7 +29,7 @@ ISearchResponse<TResult> Search<T, TResult>(ISearchRequest request)
2929
where TResult : class;
3030

3131
/// <inheritdoc/>
32-
/// <typeparam name="T">The type used to infer the index and typename as well describe the query strongly typed</typeparam>
32+
/// <typeparam name="T">The type used to infer the index and type name as well describe the query strongly typed</typeparam>
3333
/// <param name="selector">A descriptor that describes the parameters for the search operation</param>
3434
Task<ISearchResponse<T>> SearchAsync<T>(Func<SearchDescriptor<T>, ISearchRequest> selector = null) where T : class;
3535

@@ -61,7 +61,7 @@ public ISearchResponse<TResult> Search<T, TResult>(Func<SearchDescriptor<T>, ISe
6161
this.Search<TResult>(selector.InvokeOrDefault(new SearchDescriptor<T>()));
6262

6363
/// <inheritdoc/>
64-
public ISearchResponse<T> Search<T>(ISearchRequest request) where T : class =>
64+
public ISearchResponse<T> Search<T>(ISearchRequest request) where T : class =>
6565
this.Search<T, T>(request);
6666

6767
/// <inheritdoc/>
@@ -77,7 +77,7 @@ public ISearchResponse<TResult> Search<T, TResult>(ISearchRequest request)
7777

7878
/// <inheritdoc/>
7979
public Task<ISearchResponse<T>> SearchAsync<T>(Func<SearchDescriptor<T>, ISearchRequest> selector = null)
80-
where T : class =>
80+
where T : class =>
8181
this.SearchAsync<T, T>(selector);
8282

8383
/// <inheritdoc/>
@@ -87,7 +87,7 @@ public Task<ISearchResponse<TResult>> SearchAsync<T, TResult>(Func<SearchDescrip
8787
this.SearchAsync<TResult>(selector.InvokeOrDefault(new SearchDescriptor<T>()));
8888

8989
/// <inheritdoc/>
90-
public Task<ISearchResponse<T>> SearchAsync<T>(ISearchRequest request) where T : class =>
90+
public Task<ISearchResponse<T>> SearchAsync<T>(ISearchRequest request) where T : class =>
9191
this.SearchAsync<T, T>(request);
9292

9393
/// <inheritdoc/>
@@ -102,4 +102,4 @@ public Task<ISearchResponse<TResult>> SearchAsync<T, TResult>(ISearchRequest req
102102
);
103103

104104
}
105-
}
105+
}

src/Nest/Search/Search/SearchRequest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ public partial class SearchRequest<T>
177177
}
178178

179179
/// <summary>
180-
/// A descriptor wich describes a search operation for _search and _msearch
180+
/// A descriptor which describes a search operation for _search and _msearch
181181
/// </summary>
182182
public partial class SearchDescriptor<T> where T : class
183183
{

src/Nest/Search/Suggesters/Suggest/ElasticClient-Suggest.cs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace Nest
77
public partial interface IElasticClient
88
{
99
/// <summary>
10-
/// The suggest feature suggests similar looking terms based on a provided text by using a suggester.
10+
/// The suggest feature suggests similar looking terms based on a provided text by using a suggester.
1111
/// <para> </para>http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-suggesters.html
1212
/// </summary>
1313
/// <typeparam name="T">The type used to strongly type parts of the suggest operation</typeparam>
@@ -24,30 +24,28 @@ public partial interface IElasticClient
2424
Task<ISuggestResponse> SuggestAsync(ISuggestRequest request);
2525
}
2626

27-
//TODO limit scope of fluent to IndexName of T
28-
2927
public partial class ElasticClient
3028
{
3129
/// <inheritdoc/>
3230
public ISuggestResponse Suggest<T>(Func<SuggestDescriptor<T>, ISuggestRequest> selector) where T : class =>
3331
this.Suggest(selector?.Invoke(new SuggestDescriptor<T>()));
3432

3533
/// <inheritdoc/>
36-
public ISuggestResponse Suggest(ISuggestRequest request) =>
34+
public ISuggestResponse Suggest(ISuggestRequest request) =>
3735
this.Dispatcher.Dispatch<ISuggestRequest, SuggestRequestParameters, SuggestResponse>(
3836
request,
3937
this.LowLevelDispatch.SuggestDispatch<SuggestResponse>
4038
);
4139

4240
/// <inheritdoc/>
43-
public Task<ISuggestResponse> SuggestAsync<T>(Func<SuggestDescriptor<T>, ISuggestRequest> selector) where T : class =>
41+
public Task<ISuggestResponse> SuggestAsync<T>(Func<SuggestDescriptor<T>, ISuggestRequest> selector) where T : class =>
4442
this.SuggestAsync(selector?.Invoke(new SuggestDescriptor<T>()));
4543

4644
/// <inheritdoc/>
47-
public Task<ISuggestResponse> SuggestAsync(ISuggestRequest request) =>
45+
public Task<ISuggestResponse> SuggestAsync(ISuggestRequest request) =>
4846
this.Dispatcher.DispatchAsync<ISuggestRequest, SuggestRequestParameters, SuggestResponse, ISuggestResponse>(
4947
request,
5048
this.LowLevelDispatch.SuggestDispatchAsync<SuggestResponse>
5149
);
5250
}
53-
}
51+
}

src/Nest/Search/Suggesters/Suggest/SuggestRequest.cs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,21 @@
55
namespace Nest
66
{
77
[JsonConverter(typeof(SuggestRequestJsonConverter))]
8-
public partial interface ISuggestRequest
8+
public partial interface ISuggestRequest
99
{
1010
string GlobalText { get; set; }
1111
ISuggestContainer Suggest { get; set; }
1212
}
1313

14-
public partial class SuggestRequest
14+
public partial class SuggestRequest
15+
{
16+
public string GlobalText { get; set; }
17+
public ISuggestContainer Suggest { get; set; }
18+
}
19+
20+
public partial interface ISuggestRequest<T> : ISearchRequest { }
21+
22+
public partial class SuggestRequest<T>
1523
{
1624
public string GlobalText { get; set; }
1725
public ISuggestContainer Suggest { get; set; }
@@ -29,25 +37,25 @@ public partial class SuggestDescriptor<T> where T : class
2937
public SuggestDescriptor<T> GlobalText(string globalText) => Assign(a => a.GlobalText = globalText);
3038

3139
/// <summary>
32-
/// The term suggester suggests terms based on edit distance. The provided suggest text is analyzed before terms are suggested.
40+
/// The term suggester suggests terms based on edit distance. The provided suggest text is analyzed before terms are suggested.
3341
/// The suggested terms are provided per analyzed suggest text token. The term suggester doesn’t take the query into account that is part of request.
3442
/// </summary>
3543
public SuggestDescriptor<T> Term(string name, Func<TermSuggesterDescriptor<T>, ITermSuggester> suggest) =>
36-
AssignToBucket(name, suggest?.Invoke(new TermSuggesterDescriptor<T>()), (b, s) => b.Term = s);
44+
AssignToBucket(name, suggest?.Invoke(new TermSuggesterDescriptor<T>()), (b, s) => b.Term = s);
3745

3846
/// <summary>
39-
/// The phrase suggester adds additional logic on top of the term suggester to select entire corrected phrases
40-
/// instead of individual tokens weighted based on ngram-langugage models.
47+
/// The phrase suggester adds additional logic on top of the term suggester to select entire corrected phrases
48+
/// instead of individual tokens weighted based on ngram-langugage models.
4149
/// </summary>
4250
public SuggestDescriptor<T> Phrase(string name, Func<PhraseSuggesterDescriptor<T>, IPhraseSuggester> suggest) =>
43-
AssignToBucket(name, suggest?.Invoke(new PhraseSuggesterDescriptor<T>()), (b, s) => b.Phrase = s);
51+
AssignToBucket(name, suggest?.Invoke(new PhraseSuggesterDescriptor<T>()), (b, s) => b.Phrase = s);
4452

4553
/// <summary>
46-
/// The completion suggester is a so-called prefix suggester.
54+
/// The completion suggester is a so-called prefix suggester.
4755
/// It does not do spell correction like the term or phrase suggesters but allows basic auto-complete functionality.
4856
/// </summary>
4957
public SuggestDescriptor<T> Completion(string name, Func<CompletionSuggesterDescriptor<T>, ICompletionSuggester> suggest) =>
50-
AssignToBucket(name, suggest?.Invoke(new CompletionSuggesterDescriptor<T>()), (b, s) => b.Completion = s);
58+
AssignToBucket(name, suggest?.Invoke(new CompletionSuggesterDescriptor<T>()), (b, s) => b.Completion = s);
5159

5260
private SuggestDescriptor<T> AssignToBucket<TSuggester>(string name, TSuggester suggester, Action<SuggestBucket, TSuggester> assign)
5361
where TSuggester : ISuggester

src/Nest/_Generated/_Descriptors.generated.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4329,8 +4329,8 @@ public VerifyRepositoryDescriptor(Name repository) : base(r=>r.Required("reposit
43294329
public partial class SuggestDescriptor<T> : RequestDescriptorBase<SuggestDescriptor<T>,SuggestRequestParameters, ISuggestRequest>, ISuggestRequest
43304330
{
43314331
Indices ISuggestRequest.Index => Self.RouteValues.Get<Indices>("index");
4332-
/// <summary>/_suggest</summary>
4333-
public SuggestDescriptor() : base(){}
4332+
/// <summary>/_suggest. Will infer the index from the generic type</summary>
4333+
public SuggestDescriptor() : base(r => r.Required("index", (Indices)typeof(T))){}
43344334

43354335

43364336
///<summary>A comma-separated list of index names to restrict the operation; use the special string `_all` or Indices.All to perform the operation on all indices</summary>

src/Nest/_Generated/_Requests.generated.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5210,6 +5210,42 @@ public partial interface ISuggestRequest : IRequest<SuggestRequestParameters>
52105210
Indices Index { get; }
52115211
}
52125212
///<summary>Request parameters for Suggest <pre>http://www.elastic.co/guide/en/elasticsearch/reference/master/search-suggesters.html</pre></summary>
5213+
public partial class SuggestRequest<T> : PlainRequestBase<SuggestRequestParameters>, ISuggestRequest
5214+
{
5215+
protected ISuggestRequest Self => this;
5216+
Indices ISuggestRequest.Index => Self.RouteValues.Get<Indices>("index");
5217+
/// <summary>/_suggest. Will infer the index from the generic type</summary>
5218+
public SuggestRequest() : this(typeof(T)){}
5219+
5220+
5221+
/// <summary>/{index}/_suggest</summary>
5222+
///<param name="index">Optional, accepts null</param>
5223+
public SuggestRequest(Indices index) : base(r=>r.Optional("index", index)){}
5224+
5225+
5226+
///<summary>Whether specified concrete indices should be ignored when unavailable (missing or closed)</summary>
5227+
public bool IgnoreUnavailable { get { return Q<bool>("ignore_unavailable"); } set { Q("ignore_unavailable", value); } }
5228+
5229+
///<summary>Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified)</summary>
5230+
public bool AllowNoIndices { get { return Q<bool>("allow_no_indices"); } set { Q("allow_no_indices", value); } }
5231+
5232+
///<summary>Whether to expand wildcard expression to concrete indices that are open, closed or both.</summary>
5233+
public ExpandWildcards ExpandWildcards { get { return Q<ExpandWildcards>("expand_wildcards"); } set { Q("expand_wildcards", value); } }
5234+
5235+
///<summary>Specify the node or shard the operation should be performed on (default: random)</summary>
5236+
public string Preference { get { return Q<string>("preference"); } set { Q("preference", value); } }
5237+
5238+
///<summary>Specific routing value</summary>
5239+
public string Routing { get { return Q<string>("routing"); } set { Q("routing", value); } }
5240+
5241+
///<summary>The URL-encoded request definition</summary>
5242+
public string Source { get { return Q<string>("source"); } set { Q("source", value); } }
5243+
5244+
///<summary>Comma separated list of filters used to reduce the response returned by Elasticsearch</summary>
5245+
public string FilterPath { get { return Q<string>("filter_path"); } set { Q("filter_path", value); } }
5246+
5247+
}
5248+
///<summary>Request parameters for Suggest <pre>http://www.elastic.co/guide/en/elasticsearch/reference/master/search-suggesters.html</pre></summary>
52135249
public partial class SuggestRequest : PlainRequestBase<SuggestRequestParameters>, ISuggestRequest
52145250
{
52155251
protected ISuggestRequest Self => this;

src/Tests/Search/Suggesters/SuggestApiTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace Tests.Search.Suggesters
1616
1717
*/
1818
public class SuggestApiTests
19-
: ApiIntegrationTestBase<ReadOnlyCluster, ISuggestResponse, ISuggestRequest, SuggestDescriptor<Project>, SuggestRequest>
19+
: ApiIntegrationTestBase<ReadOnlyCluster, ISuggestResponse, ISuggestRequest, SuggestDescriptor<Project>, SuggestRequest<Project>>
2020
{
2121
public SuggestApiTests(ReadOnlyCluster cluster, EndpointUsage usage) : base(cluster, usage) { }
2222

@@ -30,7 +30,7 @@ protected override LazyResponses ClientUsage() => Calls(
3030
protected override int ExpectStatusCode => 200;
3131
protected override bool ExpectIsValid => true;
3232
protected override HttpMethod HttpMethod => HttpMethod.POST;
33-
protected override string UrlPath => "/_suggest";
33+
protected override string UrlPath => "/project/_suggest";
3434
protected override bool SupportsDeserialization => false;
3535

3636
protected override object ExpectJson =>
@@ -144,8 +144,8 @@ protected override LazyResponses ClientUsage() => Calls(
144144
.RealWordErrorLikelihood(0.5)
145145
);
146146

147-
protected override SuggestRequest Initializer =>
148-
new SuggestRequest
147+
protected override SuggestRequest<Project> Initializer =>
148+
new SuggestRequest<Project>
149149
{
150150
Suggest = new SuggestContainer
151151
{

0 commit comments

Comments
 (0)