Skip to content

Commit 69cf48c

Browse files
authored
Feature/7.x/low level expose deprecated paths (#3814)
* read deprecations from file * status commit * DeprecatedPaths are now rendered on the low level client allbeit obsolete * Apis with no part ended up not rendered * address PR comments * introduce compiler errrors if we generate an unmapped API * regenerate code with updated obsolete attrs
1 parent 36e9892 commit 69cf48c

File tree

72 files changed

+2795
-1789
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+2795
-1789
lines changed

src/CodeGeneration/ApiGenerator/Domain/Code/CsharpNames.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,18 @@ public string PerPathMethodName(string path)
9696
Func<string, bool> ms = s => Namespace != null && Namespace.StartsWith(s);
9797
Func<string, bool> pc = path.Contains;
9898

99+
var method = MethodName;
100+
// This is temporary for 7.0 transition period
101+
// TODO: remove in master once master in elasticsearch is scrubbed
102+
if (path.Contains("{type}") && !method.Contains("Type")) method += "UsingType";
103+
99104
if (ms("Indices") && !pc("{index}"))
100-
return (MethodName + "ForAll").Replace("AsyncForAll", "ForAllAsync");
105+
return (method + "ForAll").Replace("AsyncForAll", "ForAllAsync");
101106

102107
if (ms("Nodes") && !pc("{node_id}"))
103-
return (MethodName + "ForAll").Replace("AsyncForAll", "ForAllAsync");
108+
return (method + "ForAll").Replace("AsyncForAll", "ForAllAsync");
104109

105-
return MethodName;
110+
return method;
106111
}
107112

108113

src/CodeGeneration/ApiGenerator/Domain/Code/HighLevel/Methods/FluentSyntaxBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public string DescriptorArguments()
9797
if (!UrlParts.Any()) return codeArgs;
9898

9999
string Optional(UrlPart p) => !p.Required && SelectorIsOptional ? " = null" : string.Empty;
100-
return codeArgs + string.Join(", ", UrlParts.Select(p => $"{p.ClrTypeName} {p.Name.ToCamelCase()}{Optional(p)}")) + ", ";
100+
return codeArgs + string.Join(", ", UrlParts.Select(p => $"{p.HighLevelTypeName} {p.Name.ToCamelCase()}{Optional(p)}")) + ", ";
101101
}
102102

103103
public string SelectorArguments()
@@ -116,7 +116,7 @@ string ToArg(UrlPart p)
116116
{
117117
if (IsDocumentRequest) return "documentWithId: document";
118118

119-
if (p.ClrTypeName.StartsWith("DocumentPath"))
119+
if (p.HighLevelTypeName.StartsWith("DocumentPath"))
120120
return "documentWithId: id?.Document, index: id?.Self?.Index, id: id?.Self?.Id";
121121

122122

src/CodeGeneration/ApiGenerator/Domain/Code/HighLevel/Requests/DescriptorPartialImplementation.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@ public IEnumerable<FluentRouteSetter> GetFluentRouteSetters()
3838
var routeSetter = p.Required ? "Required" : "Optional";
3939

4040
var code =
41-
$"public {returnType} {p.InterfaceName}({p.ClrTypeName} {paramName}) => Assign({paramName}, (a,v)=>a.RouteValues.{routeSetter}(\"{p.Name}\", {routeValue}));";
41+
$"public {returnType} {p.InterfaceName}({p.HighLevelTypeName} {paramName}) => Assign({paramName}, (a,v)=>a.RouteValues.{routeSetter}(\"{p.Name}\", {routeValue}));";
4242
var xmlDoc = $"///<summary>{p.Description}</summary>";
4343
setters.Add(new FluentRouteSetter { Code = code, XmlDoc = xmlDoc });
4444
if (paramName == "index")
4545
{
4646
code = $"public {returnType} {p.InterfaceName}<TOther>() where TOther : class ";
47-
code += $"=> Assign(typeof(TOther), (a,v)=>a.RouteValues.{routeSetter}(\"{p.Name}\", ({p.ClrTypeName})v));";
47+
code += $"=> Assign(typeof(TOther), (a,v)=>a.RouteValues.{routeSetter}(\"{p.Name}\", ({p.HighLevelTypeName})v));";
4848
xmlDoc = $"///<summary>a shortcut into calling {p.InterfaceName}(typeof(TOther))</summary>";
4949
setters.Add(new FluentRouteSetter { Code = code, XmlDoc = xmlDoc });
5050
}

src/CodeGeneration/ApiGenerator/Domain/Code/LowLevel/LowLevelClientMethod.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class LowLevelClientMethod
1414
public string PerPathMethodName { get; set; }
1515
public string HttpMethod { get; set; }
1616

17-
public string DeprecatedPath { get; set; }
17+
public DeprecatedPath DeprecatedPath { get; set; }
1818
public UrlInformation Url { get; set; }
1919
public bool HasBody { get; set; }
2020
public IEnumerable<UrlPart> Parts { get; set; }
@@ -32,7 +32,9 @@ string Evaluator(Match m)
3232
}
3333

3434
var url = Path.TrimStart('/');
35-
var pattern = string.Join("|", Url.Parts.Select(p => p.Name));
35+
var options = Url.OriginalParts?.Select(p => p.Key) ?? Enumerable.Empty<string>();
36+
37+
var pattern = string.Join("|", options);
3638
var urlCode = $"\"{url}\"";
3739
if (Path.Contains("{"))
3840
{

src/CodeGeneration/ApiGenerator/Domain/Specification/ApiEndpoint.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public IReadOnlyCollection<LowLevelClientMethod> LowLevelClientMethods
120120
_lowLevelClientMethods = new List<LowLevelClientMethod>();
121121

122122
var httpMethod = PreferredHttpMethod;
123-
foreach (var path in Url.Paths)
123+
foreach (var path in Url.PathsWithDeprecations)
124124
{
125125
var methodName = CsharpNames.PerPathMethodName(path.Path);
126126
var parts = new List<UrlPart>(path.Parts);
@@ -140,7 +140,7 @@ public IReadOnlyCollection<LowLevelClientMethod> LowLevelClientMethods
140140
PerPathMethodName = methodName,
141141
HttpMethod = httpMethod,
142142
OfficialDocumentationLink = OfficialDocumentationLink,
143-
DeprecatedPath = null, //TODO
143+
DeprecatedPath = path.Deprecation,
144144
Path = path.Path,
145145
Parts = parts,
146146
Url = Url,

src/CodeGeneration/ApiGenerator/Domain/Specification/UrlInformation.cs

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
using System.Collections.Generic;
2+
using System.Data.Common;
23
using System.Linq;
4+
using System.Reflection;
5+
using CsQuery.Engine;
6+
using CsQuery.Engine.PseudoClassSelectors;
37
using Newtonsoft.Json;
48

59
namespace ApiGenerator.Domain.Specification
@@ -13,8 +17,11 @@ public class UrlInformation
1317
[JsonProperty("paths")]
1418
private IReadOnlyCollection<string> OriginalPaths { get; set; }
1519

16-
[JsonProperty("parts")]
17-
private IDictionary<string, UrlPart> OriginalParts { get; set; }
20+
[JsonProperty("parts")]
21+
public IDictionary<string, UrlPart> OriginalParts { get; set; }
22+
23+
[JsonProperty("deprecated_paths")]
24+
private IReadOnlyCollection<DeprecatedPath> DeprecatedPaths { get; set; }
1825

1926
private List<UrlPath> _paths;
2027
public IReadOnlyCollection<UrlPath> Paths
@@ -27,6 +34,42 @@ public IReadOnlyCollection<UrlPath> Paths
2734
return _paths;
2835
}
2936
}
37+
38+
private List<UrlPath> _pathsWithDeprecation;
39+
public IReadOnlyCollection<UrlPath> PathsWithDeprecations
40+
{
41+
get
42+
{
43+
if (_pathsWithDeprecation != null && _pathsWithDeprecation.Count > 0) return _pathsWithDeprecation;
44+
45+
var paths = Paths ?? new UrlPath[] {};
46+
if (DeprecatedPaths == null || DeprecatedPaths.Count == 0) return Paths;
47+
48+
//some deprecated paths describe aliases to the canonical using the same path e.g
49+
// PUT /{index}/_mapping/{type}
50+
// PUT /{index}/{type}/_mappings
51+
//
52+
//The following routine dedups these occasions and prefers either the cononical path
53+
//or the first duplicate deprecated path
54+
55+
var canonicalPartNameLookup = paths.Select(path => new HashSet<string>(path.Parts.Select(p => p.Name))).ToList();
56+
var withoutDeprecatedAliases = DeprecatedPaths
57+
.Select(deprecatedPath => new
58+
{
59+
deprecatedPath,
60+
parts = new HashSet<string>(OriginalParts.Keys.Where(k => deprecatedPath.Path.Contains($"{{{k}}}")))
61+
})
62+
.GroupBy(t => t.parts, HashSet<string>.CreateSetComparer())
63+
.Where(grouped => !canonicalPartNameLookup.Any(set => set.SetEquals(grouped.Key)))
64+
.Select(grouped => grouped.First().deprecatedPath);
65+
66+
67+
_pathsWithDeprecation = paths
68+
.Concat(withoutDeprecatedAliases.Select(p => new UrlPath(p, OriginalParts, Paths)))
69+
.ToList();
70+
return _pathsWithDeprecation;
71+
}
72+
}
3073

3174

3275
public IReadOnlyCollection<UrlPart> Parts => Paths.SelectMany(p => p.Parts).DistinctBy(p => p.Name).ToList();

src/CodeGeneration/ApiGenerator/Domain/Specification/UrlPart.cs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,45 @@
33

44
namespace ApiGenerator.Domain.Specification
55
{
6+
7+
//TODO once https://github.com/elastic/elasticsearch/pull/42346 lands
8+
// Rename this type to Deprecation and remove Path duplication
9+
public class DeprecatedPath
10+
{
11+
public string Version { get; set; }
12+
public string Path { get; set; }
13+
public string Description { get; set; }
14+
}
15+
16+
617
public class UrlPart
718
{
819
private string _description;
920

10-
public string Argument
21+
public string Argument => $"{LowLevelTypeName} {NameAsArgument}";
22+
23+
public string LowLevelTypeName
1124
{
1225
get
1326
{
1427
//TODO treat list with fixed options as Flags Enum
1528
switch (Type)
1629
{
17-
case "int":
30+
case "int": //does not occur on part
31+
case "number": //does not occur on part
1832
case "string":
19-
return Type + " " + NameAsArgument;
33+
return Type;
2034
case "list":
21-
return "string " + NameAsArgument;
35+
return "string";
2236
case "enum":
23-
return Name.ToPascalCase() + " " + NameAsArgument;
24-
case "number":
25-
return "string " + NameAsArgument;
37+
return Name.ToPascalCase();
2638
default:
27-
return Type + " " + NameAsArgument;
39+
return Type;
2840
}
2941
}
3042
}
3143

32-
public string ClrTypeName
44+
public string HighLevelTypeName
3345
{
3446
get
3547
{
@@ -116,6 +128,7 @@ public string InterfaceName
116128
public string NameAsArgument => Name.ToCamelCase();
117129
public IEnumerable<string> Options { get; set; }
118130
public bool Required { get; set; }
131+
public bool Deprecated { get; set; }
119132
public string Type { get; set; }
120133

121134
private string CleanUpDescription(string value)

src/CodeGeneration/ApiGenerator/Domain/Specification/UrlPath.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,23 @@ public class UrlPath
88
{
99
private readonly List<UrlPart> _additionalPartsForConstructor;
1010
public string Path { get; }
11+
public DeprecatedPath Deprecation { get; }
12+
1113

1214
public List<UrlPart> Parts { get; }
1315

16+
//TODO mark the parts that are deprecated
17+
//TODO this will all go away once https://github.com/elastic/elasticsearch/pull/42346 lands
18+
public UrlPath(DeprecatedPath path, IDictionary<string, UrlPart> originalParts, IReadOnlyCollection<UrlPath> allNonDeprecatedPaths)
19+
: this(path.Path, originalParts)
20+
{
21+
Deprecation = path;
22+
foreach (var part in Parts)
23+
{
24+
if (!part.Deprecated && !allNonDeprecatedPaths.Any(p => p.Path.Contains($"{{{part.Name}}}")))
25+
part.Deprecated = true;
26+
}
27+
}
1428
public UrlPath(string path, IDictionary<string, UrlPart> allParts, List<UrlPart> additionalPartsForConstructor = null)
1529
{
1630
_additionalPartsForConstructor = additionalPartsForConstructor ?? new List<UrlPart>();
@@ -30,16 +44,18 @@ orderby path.IndexOf($"{{{name}}}", StringComparison.Ordinal)
3044
Parts = parts.ToList();
3145
}
3246

33-
public string ConstructorArguments => string.Join(", ", Parts.Select(p => $"{p.ClrTypeName} {p.NameAsArgument}"));
47+
public string ConstructorArguments => string.Join(", ", Parts.Select(p => $"{p.HighLevelTypeName} {p.NameAsArgument}"));
3448
public string RequestBaseArguments =>
3549
!Parts.Any() ? string.Empty
3650
: "r => r." + string.Join(".", Parts.Select(p => $"{(p.Required ? "Required" : "Optional")}(\"{p.Name}\", {p.NameAsArgument})"));
3751

3852
public string TypedSubClassBaseArguments => string.Join(", ", Parts.Select(p => p.NameAsArgument));
3953

4054
private static string[] ResolvabeFromT = { "index"};
55+
56+
4157
public bool HasResolvableArguments => Parts.Any(p => ResolvabeFromT.Contains(p.Name));
42-
public string AutoResolveConstructorArguments => string.Join(", ", Parts.Where(p => !ResolvabeFromT.Contains(p.Name)).Select(p => $"{p.ClrTypeName} {p.NameAsArgument}"));
58+
public string AutoResolveConstructorArguments => string.Join(", ", Parts.Where(p => !ResolvabeFromT.Contains(p.Name)).Select(p => $"{p.HighLevelTypeName} {p.NameAsArgument}"));
4359

4460
public string AutoResolveBaseArguments(string generic) => string.Join(", ", Parts.Select(p => !ResolvabeFromT.Contains(p.Name) ? p.Name : $"typeof({generic})"));
4561

@@ -48,7 +64,7 @@ public string DocumentPathBaseArgument(string generic) => string.Join(", ",
4864
: ResolvabeFromT.Contains(p.Name) ? $"{p.Name} ?? typeof({generic})" : p.Name));
4965

5066
public string DocumentPathConstructorArgument(string generic) => string.Join(", ",
51-
new [] { $"{generic} documentWithId" }.Concat(_additionalPartsForConstructor.Select(p => $"{p.ClrTypeName} {p.NameAsArgument} = null")));
67+
new [] { $"{generic} documentWithId" }.Concat(_additionalPartsForConstructor.Select(p => $"{p.HighLevelTypeName} {p.NameAsArgument} = null")));
5268

5369
public string GetXmlDocs(string indent, bool skipResolvable = false, bool documentConstructor = false)
5470
{

src/CodeGeneration/ApiGenerator/RestSpecification/_Patches/clear_scroll.patch.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
"url": {
44
"path": "/_search/scroll",
55
"paths": [ "/_search/scroll" ],
6+
"parts": {
7+
"scroll_id": {
8+
"type" : "list",
9+
"description" : "A comma-separated list of scroll IDs to clear"
10+
}
11+
},
612
"deprecated_paths": [
713
{
814
"version": "7.0",

src/CodeGeneration/ApiGenerator/Views/HighLevel/Descriptors/Descriptor.cshtml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
// values part of the url path
2828
@foreach (UrlPart part in d.Parts)
2929
{
30-
<text> @(Raw(part.ClrTypeName)) @(Raw(baseInterface)).@(part.InterfaceName) => Self.RouteValues.Get@(Raw(string.Format("<{0}>",part.ClrTypeName)))("@(part.Name)");
30+
<text> @(Raw(part.HighLevelTypeName)) @(Raw(baseInterface)).@(part.InterfaceName) => Self.RouteValues.Get@(Raw(string.Format("<{0}>",part.HighLevelTypeName)))("@(part.Name)");
3131
</text>
3232
}
3333
@foreach (FluentRouteSetter c in d.GetFluentRouteSetters())
@@ -83,8 +83,9 @@
8383
}
8484
@if (names.DescriptorNotFoundInCodebase)
8585
{<text>
86-
//TODO THIS METHOD IS UNMAPPED!
87-
</text>
86+
[Obsolete("Unmapped, blacklist this API in CodeConfiguration.cs or implement @names.DescriptorName and @names.RequestName in a file called @(names.RequestName).cs in NEST's codebase", true)]
87+
public bool IsUnmapped => true;
88+
</text>
8889
}
8990
}
9091

src/CodeGeneration/ApiGenerator/Views/HighLevel/Requests/RequestImplementations.cshtml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
@foreach (var part in r.Parts)
2727
{
2828
<text> [IgnoreDataMember]
29-
@(Raw(part.ClrTypeName)) @(Raw(r.InterfaceName)).@(part.InterfaceName) => Self.RouteValues.Get@(Raw(string.Format("<{0}>", part.ClrTypeName)))("@(part.Name)");
29+
@(Raw(part.HighLevelTypeName)) @(Raw(r.InterfaceName)).@(part.InterfaceName) => Self.RouteValues.Get@(Raw(string.Format("<{0}>", part.HighLevelTypeName)))("@(part.Name)");
3030
</text>
3131
}
3232

@@ -50,8 +50,10 @@
5050
</text>
5151
}
5252
@if (names.DescriptorNotFoundInCodebase)
53-
{<text> //TODO THIS METHOD IS UNMAPPED! Expected to find @names.DescriptorName and @names.RequestName in a file called @(names.RequestName).cs in NEST's codebase
54-
</text>
53+
{<text>
54+
[Obsolete("Unmapped, blacklist this API in CodeConfiguration.cs or implement @names.DescriptorName and @names.RequestName in a file called @(names.RequestName).cs in NEST's codebase", true)]
55+
public bool IsUnmapped => true;
56+
</text>
5557
}
5658
}
5759
@if (r.NeedsGenericImplementation)

src/CodeGeneration/ApiGenerator/Views/HighLevel/Requests/RequestInterface.cshtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
@foreach (UrlPart part in i.UrlParts)
1717
{
1818
<text> [IgnoreDataMember]
19-
@(Raw(part.ClrTypeName)) @(part.InterfaceName) { get; }
19+
@(Raw(part.HighLevelTypeName)) @(part.InterfaceName) { get; }
2020
</text>
2121
}
2222
@foreach (var partialParam in i.PartialParameters)

src/CodeGeneration/ApiGenerator/Views/LowLevel/Client/Methods/MethodDocs.cshtml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
</text>
1717
}
1818
///@Raw(@"<param name=""requestParameters"">Request specific configuration such as querystring parameters &amp; request specific connection settings.</param>")
19-
@if (!string.IsNullOrEmpty(method.DeprecatedPath))
19+
@if (method.DeprecatedPath != null)
2020
{
21-
<text> [Obsolete("@method.DeprecatedPath")]
21+
<text> [Obsolete("Deprecated in version @(method.DeprecatedPath.Version): @Raw(method.DeprecatedPath.Description)")]
2222
</text>}

0 commit comments

Comments
 (0)