Skip to content

Commit 4ab5808

Browse files
committed
chore: additional NRT fixes
Signed-off-by: Vincent Biret <[email protected]>
1 parent 6827d88 commit 4ab5808

9 files changed

+100
-85
lines changed

src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationSegment.cs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public ODataOperationSegment(IEdmOperation operation, bool isEscapedFunction, IE
7272
_model = model ?? throw Error.ArgumentNull(nameof(model));
7373
}
7474

75-
private readonly IEdmModel _model;
75+
private readonly IEdmModel? _model;
7676

7777
/// <summary>
7878
/// Gets the parameter mappings.
@@ -99,7 +99,7 @@ public ODataOperationSegment(IEdmOperation operation, bool isEscapedFunction, IE
9999
public override IEdmEntityType? EntityType => null;
100100

101101
/// <inheritdoc />
102-
public override string GetPathItemName(OpenApiConvertSettings settings, HashSet<string> parameters)
102+
public override string? GetPathItemName(OpenApiConvertSettings settings, HashSet<string> parameters)
103103
{
104104
Utils.CheckArgumentNull(settings, nameof(settings));
105105

@@ -108,7 +108,7 @@ public override string GetPathItemName(OpenApiConvertSettings settings, HashSet<
108108
return FunctionName(function, settings, parameters);
109109
}
110110

111-
return OperationName(Operation, settings);
111+
return Operation is null ? null : OperationName(Operation, settings);
112112
}
113113

114114
internal IDictionary<string, string> GetNameMapping(OpenApiConvertSettings settings, HashSet<string> parameters)
@@ -155,8 +155,6 @@ private string FunctionName(IEdmFunction function, OpenApiConvertSettings settin
155155
{
156156
if (settings.EnableUriEscapeFunctionCall && IsEscapedFunction)
157157
{
158-
// Debug.Assert(function.Parameters.Count == 2); It should be verify at Edm model.
159-
// Debug.Assert(function.IsBound == true);
160158
string parameterName = function.Parameters.Last().Name;
161159
string uniqueName = Utils.GetUniqueName(parameterName, parameters);
162160
if (function.IsComposable)
@@ -171,7 +169,7 @@ private string FunctionName(IEdmFunction function, OpenApiConvertSettings settin
171169

172170
StringBuilder functionName = new();
173171
functionName.Append(OperationName(function, settings));
174-
functionName.Append("(");
172+
functionName.Append('(');
175173

176174
int skip = function.IsBound ? 1 : 0;
177175
functionName.Append(string.Join(",", function.Parameters.Skip(skip).Select(p =>
@@ -183,7 +181,7 @@ private string FunctionName(IEdmFunction function, OpenApiConvertSettings settin
183181
: p.Name + $"={quote}{{{uniqueName}}}{quote}";
184182
})));
185183

186-
functionName.Append(")");
184+
functionName.Append(')');
187185

188186
return functionName.ToString();
189187
}

src/Microsoft.OpenApi.OData.Reader/Edm/ODataSegment.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public abstract class ODataSegment
8686
/// <summary>
8787
/// Gets the entity type of current segment.
8888
/// </summary>
89-
public virtual IEdmEntityType EntityType => throw new NotImplementedException();
89+
public virtual IEdmEntityType? EntityType => throw new NotImplementedException();
9090

9191
/// <summary>
9292
/// Gets the kind of this segment.
@@ -96,14 +96,14 @@ public abstract class ODataSegment
9696
/// <summary>
9797
/// Gets the identifier of this segment.
9898
/// </summary>
99-
public abstract string Identifier { get; }
99+
public abstract string? Identifier { get; }
100100

101101
/// <summary>
102102
/// Gets the path item name for this segment.
103103
/// </summary>
104104
/// <param name="settings">The settings.</param>
105105
/// <returns>The path item name.</returns>
106-
public string GetPathItemName(OpenApiConvertSettings settings)
106+
public string? GetPathItemName(OpenApiConvertSettings settings)
107107
{
108108
return GetPathItemName(settings, []);
109109
}
@@ -125,7 +125,7 @@ public string GetPathHash(OpenApiConvertSettings settings, ODataPath? path = def
125125
/// <param name="settings">The settings.</param>
126126
/// <param name="parameters">The existing parameters.</param>
127127
/// <returns>The path item name.</returns>
128-
public abstract string GetPathItemName(OpenApiConvertSettings settings, HashSet<string> parameters);
128+
public abstract string? GetPathItemName(OpenApiConvertSettings settings, HashSet<string> parameters);
129129

130130
/// <summary>
131131
/// Returns the list of <see cref="IEdmVocabularyAnnotatable"/> this segment refers to.

src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs

Lines changed: 45 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
44
// ------------------------------------------------------------
55

6+
using System;
67
using System.Collections.Generic;
78
using System.Linq;
89
using System.Text.Json.Nodes;
@@ -32,22 +33,22 @@ protected EdmOperationOperationHandler(OpenApiDocument document) : base(document
3233
{
3334

3435
}
35-
private OperationRestrictionsType _operationRestriction;
36+
private OperationRestrictionsType? _operationRestriction;
3637

3738
/// <summary>
3839
/// Gets the navigation source.
3940
/// </summary>
40-
protected IEdmNavigationSource NavigationSource { get; private set; }
41+
protected IEdmNavigationSource? NavigationSource { get; private set; }
4142

4243
/// <summary>
4344
/// Gets the Edm operation.
4445
/// </summary>
45-
protected IEdmOperation EdmOperation { get; private set; }
46+
protected IEdmOperation? EdmOperation { get; private set; }
4647

4748
/// <summary>
4849
/// Gets the OData operation segment.
4950
/// </summary>
50-
protected ODataOperationSegment OperationSegment { get; private set; }
51+
protected ODataOperationSegment? OperationSegment { get; private set; }
5152

5253
/// <summary>
5354
/// Gets a value indicating whether the path has type cast segment or not.
@@ -60,31 +61,38 @@ protected override void Initialize(ODataContext context, ODataPath path)
6061
base.Initialize(context, path);
6162

6263
// It's bound operation, the first segment must be the navigaiton source.
63-
ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
64-
NavigationSource = navigationSourceSegment.NavigationSource;
64+
if (path.FirstSegment is ODataNavigationSourceSegment navigationSourceSegment)
65+
NavigationSource = navigationSourceSegment.NavigationSource;
6566

66-
OperationSegment = path.LastSegment as ODataOperationSegment;
67-
EdmOperation = OperationSegment.Operation;
67+
if (path.LastSegment is ODataOperationSegment opSegment)
68+
{
69+
OperationSegment = opSegment;
70+
EdmOperation = opSegment.Operation;
71+
}
6872

6973
HasTypeCast = path.Segments.Any(s => s is ODataTypeCastSegment);
7074

71-
_operationRestriction = Context.Model.GetRecord<OperationRestrictionsType>(TargetPath, CapabilitiesConstants.OperationRestrictions);
72-
var operationRestrictions = Context.Model.GetRecord<OperationRestrictionsType>(EdmOperation, CapabilitiesConstants.OperationRestrictions);
73-
_operationRestriction?.MergePropertiesIfNull(operationRestrictions);
74-
_operationRestriction ??= operationRestrictions;
75+
if (!string.IsNullOrEmpty(TargetPath))
76+
_operationRestriction = Context?.Model.GetRecord<OperationRestrictionsType>(TargetPath, CapabilitiesConstants.OperationRestrictions);
77+
if (Context is not null && EdmOperation is not null &&
78+
Context.Model.GetRecord<OperationRestrictionsType>(EdmOperation, CapabilitiesConstants.OperationRestrictions) is { } operationRestrictions)
79+
{
80+
_operationRestriction?.MergePropertiesIfNull(operationRestrictions);
81+
_operationRestriction ??= operationRestrictions;
82+
}
7583
}
7684

7785
/// <inheritdoc/>
7886
protected override void SetBasicInfo(OpenApiOperation operation)
7987
{
8088
// Summary
81-
operation.Summary = "Invoke " + (EdmOperation.IsAction() ? "action " : "function ") + EdmOperation.Name;
89+
operation.Summary = "Invoke " + (EdmOperation?.IsAction() ?? false ? "action " : "function ") + EdmOperation?.Name;
8290

8391
// Description
84-
operation.Description = Context.Model.GetDescriptionAnnotation(TargetPath) ?? Context.Model.GetDescriptionAnnotation(EdmOperation);
92+
operation.Description = (string.IsNullOrEmpty(TargetPath) ? null :Context?.Model.GetDescriptionAnnotation(TargetPath)) ?? Context?.Model.GetDescriptionAnnotation(EdmOperation);
8593

8694
// OperationId
87-
if (Context.Settings.EnableOperationId)
95+
if (Context is {Settings.EnableOperationId: true} && Path is not null)
8896
{
8997
// When the key segment is available,
9098
// its EntityType name will be used
@@ -97,7 +105,7 @@ protected override void SetBasicInfo(OpenApiOperation operation)
97105
{
98106
if (segment is ODataKeySegment keySegment)
99107
{
100-
if (!keySegment.IsAlternateKey)
108+
if (!keySegment.IsAlternateKey && segment is {EntityType: not null})
101109
{
102110
identifiers.Add(segment.EntityType.Name);
103111
continue;
@@ -113,7 +121,7 @@ protected override void SetBasicInfo(OpenApiOperation operation)
113121
identifiers.Add(keySegment.Identifier);
114122
}
115123
}
116-
else if (segment is ODataOperationSegment opSegment)
124+
else if (segment is ODataOperationSegment {Identifier: not null} opSegment)
117125
{
118126
if (opSegment.Operation is IEdmFunction function && Context.Model.IsOperationOverload(function))
119127
{
@@ -123,9 +131,9 @@ protected override void SetBasicInfo(OpenApiOperation operation)
123131
: (pathHash + opSegment.GetPathHash(Context.Settings)).GetHashSHA256()[..4];
124132
}
125133

126-
identifiers.Add(segment.Identifier);
134+
identifiers.Add(opSegment.Identifier);
127135
}
128-
else
136+
else if (!string.IsNullOrEmpty(segment.Identifier))
129137
{
130138
identifiers.Add(segment.Identifier);
131139
}
@@ -154,11 +162,12 @@ protected override void SetTags(OpenApiOperation operation)
154162
{
155163
Name = tagName,
156164
};
165+
tag.Extensions ??= new Dictionary<string, IOpenApiExtension>();
157166
tag.Extensions.Add(Constants.xMsTocType, new OpenApiAny("container"));
158167
operation.Tags ??= new HashSet<OpenApiTagReference>();
159168
operation.Tags.Add(new OpenApiTagReference(tag.Name, _document));
160169

161-
Context.AppendTag(tag);
170+
Context?.AppendTag(tag);
162171

163172
base.SetTags(operation);
164173
}
@@ -169,12 +178,13 @@ protected override void SetTags(OpenApiOperation operation)
169178
/// <param name="tagName">The generated tag name.</param>
170179
/// <param name="skip">The number of segments to skip.</param>
171180
private void GenerateTagName(out string tagName, int skip = 1)
172-
{
181+
{
182+
if (Path is null) throw new InvalidOperationException("Path is null.");
173183
var targetSegment = Path.Segments.Reverse().Skip(skip).FirstOrDefault();
174184

175185
switch (targetSegment)
176186
{
177-
case ODataNavigationPropertySegment:
187+
case ODataNavigationPropertySegment when Context is not null:
178188
tagName = EdmModelHelper.GenerateNavigationPropertyPathTagName(Path, Context);
179189
break;
180190
case ODataOperationImportSegment:
@@ -184,7 +194,7 @@ private void GenerateTagName(out string tagName, int skip = 1)
184194
GenerateTagName(out tagName, skip);
185195
break;
186196
default:
187-
tagName = NavigationSource.Name + "." + NavigationSource.EntityType.Name;
197+
tagName = NavigationSource?.Name + "." + NavigationSource?.EntityType.Name;
188198
if (EdmOperation.IsAction())
189199
{
190200
tagName += ".Actions";
@@ -202,17 +212,17 @@ protected override void SetParameters(OpenApiOperation operation)
202212
{
203213
base.SetParameters(operation);
204214

205-
if (EdmOperation.IsFunction())
215+
if (EdmOperation.IsFunction() && EdmOperation is IEdmFunction function)
206216
{
207-
IEdmFunction function = (IEdmFunction)EdmOperation;
208217
AppendSystemQueryOptions(function, operation);
209218
}
210219
}
211220

212221
/// <inheritdoc/>
213222
protected override void SetResponses(OpenApiOperation operation)
214223
{
215-
operation.Responses = Context.CreateResponses(EdmOperation, _document);
224+
if (EdmOperation is not null && Context is not null)
225+
operation.Responses = Context.CreateResponses(EdmOperation, _document);
216226
base.SetResponses(operation);
217227
}
218228

@@ -224,7 +234,7 @@ protected override void SetSecurity(OpenApiOperation operation)
224234
return;
225235
}
226236

227-
operation.Security = Context.CreateSecurityRequirements(_operationRestriction.Permissions, _document).ToList();
237+
operation.Security = Context?.CreateSecurityRequirements(_operationRestriction.Permissions, _document).ToList();
228238
}
229239

230240
/// <inheritdoc/>
@@ -248,8 +258,9 @@ protected override void AppendCustomParameters(OpenApiOperation operation)
248258

249259
private void AppendSystemQueryOptions(IEdmFunction function, OpenApiOperation operation)
250260
{
251-
if (function.ReturnType.IsCollection())
261+
if (function.ReturnType.IsCollection() && Context is not null)
252262
{
263+
operation.Parameters ??= [];
253264
// $top
254265
if (Context.CreateTop(function, _document) is {} topParameter)
255266
{
@@ -306,10 +317,10 @@ private void AppendSystemQueryOptions(IEdmFunction function, OpenApiOperation op
306317
/// <inheritdoc/>
307318
protected override void SetCustomLinkRelType()
308319
{
309-
if (Context.Settings.CustomHttpMethodLinkRelMapping != null && EdmOperation != null)
320+
if (Context is {Settings.CustomHttpMethodLinkRelMapping: not null} && EdmOperation != null)
310321
{
311322
LinkRelKey key = EdmOperation.IsAction() ? LinkRelKey.Action : LinkRelKey.Function;
312-
Context.Settings.CustomHttpMethodLinkRelMapping.TryGetValue(key, out string linkRelValue);
323+
Context.Settings.CustomHttpMethodLinkRelMapping.TryGetValue(key, out var linkRelValue);
313324
CustomLinkRel = linkRelValue;
314325
}
315326
}
@@ -321,9 +332,9 @@ protected override void SetExternalDocs(OpenApiOperation operation)
321332
{
322333
var externalDocs = (string.IsNullOrEmpty(TargetPath), string.IsNullOrEmpty(CustomLinkRel)) switch
323334
{
324-
(_, true) => null,
325335
(false, false) => Context.Model.GetLinkRecord(TargetPath!, CustomLinkRel!),
326-
(true, false) => Context.Model.GetLinkRecord(EdmOperation, CustomLinkRel!),
336+
(true, false) when EdmOperation is not null => Context.Model.GetLinkRecord(EdmOperation, CustomLinkRel!),
337+
(_, _) => null,
327338
};
328339

329340
if (externalDocs != null)
@@ -340,9 +351,9 @@ protected override void SetExternalDocs(OpenApiOperation operation)
340351
// <inheritdoc/>
341352
protected override void SetExtensions(OpenApiOperation operation)
342353
{
343-
if (Context is { Settings.EnablePagination: true } && EdmOperation.ReturnType?.TypeKind() == EdmTypeKind.Collection)
354+
if (Context is { Settings.EnablePagination: true } && EdmOperation?.ReturnType?.TypeKind() == EdmTypeKind.Collection)
344355
{
345-
JsonObject extension = new JsonObject
356+
var extension = new JsonObject
346357
{
347358
{ "nextLinkName", "@odata.nextLink"},
348359
{ "operationName", Context.Settings.PageableOperationName}

src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetOperationHandler.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
using Microsoft.OData.Edm;
77
using Microsoft.OpenApi.Any;
8+
using Microsoft.OpenApi.Interfaces;
89
using Microsoft.OpenApi.Models;
910
using Microsoft.OpenApi.Models.References;
1011
using Microsoft.OpenApi.OData.Common;
@@ -30,27 +31,26 @@ protected EntitySetOperationHandler(OpenApiDocument document) : base(document)
3031
/// <summary>
3132
/// Gets/sets the <see cref="IEdmEntitySet"/>.
3233
/// </summary>
33-
protected IEdmEntitySet EntitySet { get; private set; }
34+
protected IEdmEntitySet? EntitySet { get; private set; }
3435

3536
/// <inheritdoc/>
3637
protected override void Initialize(ODataContext context, ODataPath path)
3738
{
3839
base.Initialize(context, path);
3940

4041
// get the entity set.
41-
ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
42-
43-
EntitySet = navigationSourceSegment.NavigationSource as IEdmEntitySet;
42+
if (path.FirstSegment is ODataNavigationSourceSegment {NavigationSource: IEdmEntitySet navigationSource})
43+
EntitySet = navigationSource;
4444
}
4545

4646
/// <inheritdoc/>
4747
protected override void SetTags(OpenApiOperation operation)
4848
{
49-
var tagName = EntitySet.Name + "." + EntitySet.EntityType.Name;
49+
var tagName = EntitySet?.Name + "." + EntitySet?.EntityType.Name;
5050
operation.Tags ??= new HashSet<OpenApiTagReference>();
5151
operation.Tags.Add(new OpenApiTagReference(tagName, _document));
5252

53-
Context.AddExtensionToTag(tagName, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag()
53+
Context?.AddExtensionToTag(tagName, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag()
5454
{
5555
Name = tagName
5656
});
@@ -61,6 +61,7 @@ protected override void SetTags(OpenApiOperation operation)
6161
/// <inheritdoc/>
6262
protected override void SetExtensions(OpenApiOperation operation)
6363
{
64+
operation.Extensions ??= new Dictionary<string, IOpenApiExtension>();
6465
operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiAny("operation"));
6566

6667
base.SetExtensions(operation);
@@ -69,10 +70,10 @@ protected override void SetExtensions(OpenApiOperation operation)
6970
/// <inheritdoc/>
7071
protected override void SetExternalDocs(OpenApiOperation operation)
7172
{
72-
if (Context.Settings.ShowExternalDocs)
73+
if (Context is {Settings.ShowExternalDocs: true} && CustomLinkRel is not null)
7374
{
74-
var externalDocs = Context.Model.GetLinkRecord(TargetPath, CustomLinkRel) ??
75-
Context.Model.GetLinkRecord(EntitySet, CustomLinkRel);
75+
var externalDocs = (string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetLinkRecord(TargetPath, CustomLinkRel)) ??
76+
(EntitySet is null ? null : Context.Model.GetLinkRecord(EntitySet, CustomLinkRel));
7677

7778
if (externalDocs != null)
7879
{

0 commit comments

Comments
 (0)