Skip to content

Commit c1aa5a6

Browse files
authored
Add model reference support to library and command line utility. (#81)
* Support many conversion options in the command-line tool. Support local reference files in file-based csdl in the library and command-line tool. * Added tests for references. * Updates from github review.
1 parent f6f26df commit c1aa5a6

17 files changed

+497
-41
lines changed

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

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ public static bool IsAssignableFrom(this IEdmEntityType baseType, IEdmEntityType
162162
}
163163

164164
/// <summary>
165-
/// Check whether the operaiton is overload in the model.
165+
/// Check whether the operation is overload in the model.
166166
/// </summary>
167167
/// <param name="model">The Edm model.</param>
168168
/// <param name="operation">The test operations.</param>
@@ -172,7 +172,7 @@ public static bool IsOperationOverload(this IEdmModel model, IEdmOperation opera
172172
Utils.CheckArgumentNull(model, nameof(model));
173173
Utils.CheckArgumentNull(operation, nameof(operation));
174174

175-
return model.SchemaElements.OfType<IEdmOperation>()
175+
return model.GetAllElements().OfType<IEdmOperation>()
176176
.Where(o => o.IsBound == operation.IsBound && o.FullName() == operation.FullName() &&
177177
o.Parameters.First().Type.Definition == operation.Parameters.First().Type.Definition
178178
).Count() > 1;
@@ -197,5 +197,28 @@ public static bool IsOperationImportOverload(this IEdmModel model, IEdmOperation
197197
return model.EntityContainer.OperationImports()
198198
.Where(o => o.Operation.IsBound == operationImport.Operation.IsBound && o.Name == operationImport.Name).Count() > 1;
199199
}
200+
201+
/// <summary>
202+
/// Get all of the elements in the model and its referenced models.
203+
/// </summary>
204+
/// <returns>All the elements.</returns>
205+
public static IEnumerable<IEdmSchemaElement> GetAllElements(this IEdmModel model)
206+
{
207+
foreach (var element in model.SchemaElements.Where(el =>
208+
!ODataConstants.StandardNamespaces.Any(std => el.Namespace.StartsWith(std))))
209+
{
210+
yield return element;
211+
}
212+
213+
foreach (var refModel in model.ReferencedModels)
214+
{
215+
foreach (var element in refModel.SchemaElements.Where(el =>
216+
!ODataConstants.StandardNamespaces.Any(std => el.Namespace.StartsWith(std))))
217+
{
218+
yield return element;
219+
}
220+
}
221+
}
222+
200223
}
201224
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ private IDictionary<string, IList<IEdmOperation>> LoadEdmOperations()
7171
{
7272
IDictionary<string, IList<IEdmOperation>> edmOperationDict = new Dictionary<string, IList<IEdmOperation>>();
7373

74-
foreach (var edmOperation in Model.SchemaElements.OfType<IEdmOperation>().Where(e => e.IsBound))
74+
foreach (var edmOperation in Model.GetAllElements().OfType<IEdmOperation>().Where(e => e.IsBound))
7575
{
7676
IEdmOperationParameter bindingParameter = edmOperation.Parameters.First();
7777

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ private bool ShouldExpandNavigationProperty(IEdmNavigationProperty navigationPro
294294
/// </summary>
295295
private void RetrieveBoundOperationPaths()
296296
{
297-
foreach (var edmOperation in _model.SchemaElements.OfType<IEdmOperation>().Where(e => e.IsBound))
297+
foreach (var edmOperation in _model.GetAllElements().OfType<IEdmOperation>().Where(e => e.IsBound))
298298
{
299299
if (!CanFilter(edmOperation))
300300
{

src/Microsoft.OpenApi.OData.Reader/Generator/EdmSpatialTypeVisitor.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// ------------------------------------------------------------
55

66
using Microsoft.OData.Edm;
7+
using Microsoft.OpenApi.OData.Edm;
78

89
namespace Microsoft.OpenApi.OData.Generator
910
{
@@ -30,7 +31,7 @@ public void Visit(IEdmModel model)
3031
return;
3132
}
3233

33-
foreach (var element in model.SchemaElements)
34+
foreach (var element in model.GetAllElements())
3435
{
3536
switch (element.SchemaElementKind)
3637
{

src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiExampleGenerator.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@ public static IDictionary<string, OpenApiExample> CreateExamples(this ODataConte
3434

3535
// Each entity type, complex type, enumeration type, and type definition directly
3636
// or indirectly used in the paths field is represented as a name / value pair of the schemas map.
37-
foreach (var element in context.Model.SchemaElements.Where(c => !c.Namespace.StartsWith("Org.OData.")))
37+
// Ideally this would be driven off the types used in the paths, but in practice, it is simply
38+
// all of the types present in the model.
39+
IEnumerable<IEdmSchemaElement> elements = context.Model.GetAllElements();
40+
41+
foreach (var element in elements)
3842
{
3943
switch (element.SchemaElementKind)
4044
{

src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ public static IDictionary<string, OpenApiSchema> CreateSchemas(this ODataContext
3838

3939
// Each entity type, complex type, enumeration type, and type definition directly
4040
// or indirectly used in the paths field is represented as a name / value pair of the schemas map.
41-
foreach (var element in context.Model.SchemaElements.Where(c => !c.Namespace.StartsWith("Org.OData.")))
41+
// Ideally this would be driven off the types used in the paths, but in practice, it is simply
42+
// all of the types present in the model.
43+
IEnumerable<IEdmSchemaElement> elements = context.Model.GetAllElements();
44+
45+
foreach (var element in elements)
4246
{
4347
switch (element.SchemaElementKind)
4448
{
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// ------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
4+
// ------------------------------------------------------------
5+
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using System.Text;
10+
using System.Threading.Tasks;
11+
12+
namespace Microsoft.OpenApi.OData
13+
{
14+
internal static class ODataConstants
15+
{
16+
/// <summary>
17+
/// Namespaces used in standard included models.
18+
/// </summary>
19+
public static IList<string> StandardNamespaces = new List<string>
20+
{
21+
"Org.OData.",
22+
"Edm",
23+
"OData.Community.",
24+
};
25+
26+
}
27+
}

src/OoasUtil/ComLineProcesser.cs

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ public ComLineProcesser(string[] args)
4545
/// </summary>
4646
public OpenApiFormat? Format { get; private set; }
4747

48+
/// <summary>
49+
/// Whether KeyAsSegment is used.
50+
/// </summary>
51+
public bool? KeyAsSegment { get; private set; }
52+
4853
/// <summary>
4954
/// Output OpenApi Specification Version.
5055
/// </summary>
@@ -60,6 +65,31 @@ public ComLineProcesser(string[] args)
6065
/// </summary>
6166
public bool IsLocalFile { get; private set; }
6267

68+
/// <summary>
69+
/// Set the output to produce all derived types in responses.
70+
/// </summary>
71+
public bool? DerivedTypesReferencesForResponses { get; private set; }
72+
73+
/// <summary>
74+
/// Set the output to expect all derived types in request bodies.
75+
/// </summary>
76+
public bool? DerivedTypesReferencesForRequestBody { get; private set; }
77+
78+
/// <summary>
79+
/// Set the output to expose pagination for collections.
80+
/// </summary>
81+
public bool? EnablePagination { get; private set; }
82+
83+
/// <summary>
84+
/// tSet the output to use unqualified calls for bound operations.
85+
/// </summary>
86+
public bool? EnableUnqualifiedCall { get; private set; }
87+
88+
/// <summary>
89+
/// tDisable examples in the schema.
90+
/// </summary>
91+
public bool? DisableSchemaExamples { get; private set; }
92+
6393
/// <summary>
6494
/// Process the arguments.
6595
/// </summary>
@@ -98,6 +128,14 @@ public bool Process()
98128
i++;
99129
break;
100130

131+
case "--keyassegment":
132+
case "-k":
133+
if (!ProcessKeyAsSegment(true))
134+
{
135+
return false;
136+
}
137+
break;
138+
101139
case "--yaml":
102140
case "-y":
103141
if (!ProcessTarget(OpenApiFormat.Yaml))
@@ -132,6 +170,46 @@ public bool Process()
132170
i++;
133171
break;
134172

173+
case "--derivedtypesreferencesforresponses":
174+
case "-drs":
175+
if (!ProcessDerivedTypesReferencesForResponses(true))
176+
{
177+
return false;
178+
}
179+
break;
180+
181+
case "--derivedtypesreferencesforrequestbody":
182+
case "-drq":
183+
if (!ProcessDerivedTypesReferencesForRequestBody(true))
184+
{
185+
return false;
186+
}
187+
break;
188+
189+
case "--enablepagination":
190+
case "-p":
191+
if (!ProcessEnablePagination(true))
192+
{
193+
return false;
194+
}
195+
break;
196+
197+
case "--enableunqualifiedcall":
198+
case "-u":
199+
if (!ProcessEnableUnqualifiedCall(true))
200+
{
201+
return false;
202+
}
203+
break;
204+
205+
case "--disableschemaexamples":
206+
case "-x":
207+
if (!ProcessDisableSchemaExamples(true))
208+
{
209+
return false;
210+
}
211+
break;
212+
135213
default:
136214
PrintUsage();
137215
return false;
@@ -155,6 +233,36 @@ public bool Process()
155233
Version = OpenApiSpecVersion.OpenApi3_0;
156234
}
157235

236+
if (KeyAsSegment == null)
237+
{
238+
KeyAsSegment = false;
239+
}
240+
241+
if (DerivedTypesReferencesForResponses == null)
242+
{
243+
DerivedTypesReferencesForResponses = false;
244+
}
245+
246+
if (DerivedTypesReferencesForRequestBody == null)
247+
{
248+
DerivedTypesReferencesForRequestBody = false;
249+
}
250+
251+
if (EnablePagination == null)
252+
{
253+
EnablePagination = false;
254+
}
255+
256+
if (EnableUnqualifiedCall == null)
257+
{
258+
EnableUnqualifiedCall = false;
259+
}
260+
261+
if (DisableSchemaExamples == null)
262+
{
263+
DisableSchemaExamples = false;
264+
}
265+
158266
_continue = ValidateArguments();
159267
return _continue;
160268
}
@@ -198,6 +306,84 @@ private bool ProcessTarget(OpenApiFormat format)
198306
return true;
199307
}
200308

309+
private bool ProcessKeyAsSegment(bool keyAsSegment)
310+
{
311+
if (KeyAsSegment != null)
312+
{
313+
Console.WriteLine("[Error:] Multiple [--keyassegment|-k] are not allowed.\n");
314+
PrintUsage();
315+
return false;
316+
}
317+
318+
KeyAsSegment = keyAsSegment;
319+
return true;
320+
}
321+
322+
private bool ProcessDerivedTypesReferencesForResponses(bool derivedTypesReferencesForResponses)
323+
{
324+
if (DerivedTypesReferencesForResponses != null)
325+
{
326+
Console.WriteLine("[Error:] Multiple [--derivedtypesreferencesforresponses|-drs] are not allowed.\n");
327+
PrintUsage();
328+
return false;
329+
}
330+
331+
DerivedTypesReferencesForResponses = derivedTypesReferencesForResponses;
332+
return true;
333+
}
334+
335+
private bool ProcessDerivedTypesReferencesForRequestBody(bool derivedTypesReferencesForRequestBody)
336+
{
337+
if (DerivedTypesReferencesForRequestBody != null)
338+
{
339+
Console.WriteLine("[Error:] Multiple [--derivedtypesreferencesforrequestbody|-drq] are not allowed.\n");
340+
PrintUsage();
341+
return false;
342+
}
343+
344+
DerivedTypesReferencesForRequestBody = derivedTypesReferencesForRequestBody;
345+
return true;
346+
}
347+
348+
private bool ProcessEnablePagination(bool enablePagination)
349+
{
350+
if (EnablePagination != null)
351+
{
352+
Console.WriteLine("[Error:] Multiple [--enablepagination|-p] are not allowed.\n");
353+
PrintUsage();
354+
return false;
355+
}
356+
357+
EnablePagination = enablePagination;
358+
return true;
359+
}
360+
361+
private bool ProcessEnableUnqualifiedCall(bool enableUnqualifiedCall)
362+
{
363+
if (EnableUnqualifiedCall != null)
364+
{
365+
Console.WriteLine("[Error:] Multiple [--enableunqualifiedcall|-u] are not allowed.\n");
366+
PrintUsage();
367+
return false;
368+
}
369+
370+
EnableUnqualifiedCall = enableUnqualifiedCall;
371+
return true;
372+
}
373+
374+
private bool ProcessDisableSchemaExamples(bool disableSchemaExamples)
375+
{
376+
if (DisableSchemaExamples != null)
377+
{
378+
Console.WriteLine("[Error:] Multiple [--disableschemaexamples|-x] are not allowed.\n");
379+
PrintUsage();
380+
return false;
381+
}
382+
383+
DisableSchemaExamples = disableSchemaExamples;
384+
return true;
385+
}
386+
201387
private bool ProcessTarget(int version)
202388
{
203389
if (Version != null)
@@ -256,6 +442,12 @@ public static void PrintUsage()
256442
sb.Append(" --version|-v\t\t\tDisplay version.\n");
257443
sb.Append(" --input|-i CsdlFileOrUrl\tSet the CSDL file name or the OData Service Url.\n");
258444
sb.Append(" --output|-o OutputFile\tSet the output file name.\n");
445+
sb.Append(" --keyassegment|-k\t\t\tSet the output to use key-as-segment style URLs.\n");
446+
sb.Append(" --derivedtypesreferencesforresponses|-drs\t\t\tSet the output to produce all derived types in responses.\n");
447+
sb.Append(" --derivedtypesreferencesforrequestbody|-drq\t\t\tSet the output to expect all derived types in request bodies.\n");
448+
sb.Append(" --enablepagination|-p\t\t\tSet the output to expose pagination for collections.\n");
449+
sb.Append(" --enableunqualifiedcall|-u\t\t\tSet the output to use unqualified calls for bound operations.\n");
450+
sb.Append(" --disableschemaexamples|-x\t\t\tDisable examples in the schema.\n");
259451
sb.Append(" --json|-j\t\t\tSet the output format as JSON.\n");
260452
sb.Append(" --yaml|-y\t\t\tSet the output format as YAML.\n");
261453
sb.Append(" --specversion|-s IntVersion\tSet the OpenApi Specification version of the output. Only 2 or 3 are supported.\n");

0 commit comments

Comments
 (0)