Skip to content

Commit

Permalink
- fixes #1270 a bug where missing schema title would make union types…
Browse files Browse the repository at this point in the history
… fail
  • Loading branch information
baywet committed Mar 15, 2022
1 parent e2d45e6 commit 7dd639e
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed a bug where unnecessary namespaces would be added to models generation #1273
- Fixed a bug where Go byte arrays would not write deserializers properly.
- Fixed a bug where integers would not be recognized when type is not number.
- Fixed a bug where union types with primitive member types would fail to generate #1270
- Fixed a bug where union types with inline schema member types would fail to generate #1270

## [0.0.18] - 2022-03-14

Expand Down
6 changes: 3 additions & 3 deletions src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ public static IEnumerable<string> GetSchemaTitles(this OpenApiSchema schema) {
else if(schema.Items != null)
return schema.Items.GetSchemaTitles();
else if(!string.IsNullOrEmpty(schema.Title))
return new List<string>{ schema.Title };
return new string[] { schema.Title };
else if(schema.AnyOf.Any())
return schema.AnyOf.FlattenIfRequired(classNamesFlattener);
else if(schema.AllOf.Any())
return schema.AllOf.FlattenIfRequired(classNamesFlattener);
else if(schema.OneOf.Any())
return schema.OneOf.FlattenIfRequired(classNamesFlattener);
else if(!string.IsNullOrEmpty(schema.Reference?.Id))
return new List<string>{schema.Reference.Id.Split('/').Last().Split('.').Last()};
return new string[] {schema.Reference.Id.Split('/').Last().Split('.').Last()};
else if(!string.IsNullOrEmpty(schema.Xml?.Name))
return new List<string>{schema.Xml.Name};
return new string[] {schema.Xml.Name};
else return Enumerable.Empty<string>();
}
public static IEnumerable<OpenApiSchema> GetNonEmptySchemas(this OpenApiSchema schema) {
Expand Down
7 changes: 7 additions & 0 deletions src/Kiota.Builder/KiotaBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -810,12 +810,19 @@ private CodeTypeBase CreateUnionModelDeclaration(OpenApiUrlTreeNode currentNode,
var unionType = new CodeUnionType {
Name = currentNode.GetClassName(operation: operation, suffix: suffixForInlineSchema, schema: schema),
};
var membersWithNoName = 0;
foreach(var currentSchema in schemas) {
var shortestNamespaceName = currentSchema.Reference == null ? currentNode.GetNodeNamespaceFromPath(config.ClientNamespaceName) : GetModelsNamespaceNameFromReferenceId(currentSchema.Reference.Id);
var shortestNamespace = rootNamespace.FindNamespaceByName(shortestNamespaceName);
if(shortestNamespace == null)
shortestNamespace = rootNamespace.AddNamespace(shortestNamespaceName);
var className = currentSchema.GetSchemaTitle();
if (string.IsNullOrEmpty(className))
if(GetPrimitiveType(currentSchema) is CodeType primitiveType && !string.IsNullOrEmpty(primitiveType.Name)) {
unionType.AddType(primitiveType);
continue;
} else
className = $"{unionType.Name}Member{++membersWithNoName}";
var codeDeclaration = AddModelDeclarationIfDoesntExist(currentNode, currentSchema, className, shortestNamespace);
unionType.AddType(new CodeType {
TypeDefinition = codeDeclaration,
Expand Down
143 changes: 143 additions & 0 deletions tests/Kiota.Builder.Tests/KiotaBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,149 @@ public void AddsDiscriminatorMappings(){
Assert.NotNull(castType.TypeDefinition);
Assert.Equal(directoryObjectClass, castType.TypeDefinition);
}
[Fact]
public void UnionOfPrimitiveTypesWorks() {
var simpleObjet = new OpenApiSchema {
Type = "object",
Properties = new Dictionary<string, OpenApiSchema> {
{
"id", new OpenApiSchema {
Type = "string"
}
}
},
Reference = new OpenApiReference {
Id = "subNS.simpleObject",
Type = ReferenceType.Schema
},
UnresolvedReference = false
};
var document = new OpenApiDocument() {
Paths = new OpenApiPaths() {
["unionType"] = new OpenApiPathItem() {
Operations = {
[OperationType.Get] = new OpenApiOperation() {
Responses = new OpenApiResponses
{
["200"] = new OpenApiResponse {
Content = {
["application/json"] = new OpenApiMediaType {
Schema = new OpenApiSchema {
OneOf = new List<OpenApiSchema> {
simpleObjet,
new OpenApiSchema {
Type = "number"
}
}
}
}
}
},
}
}
}
}
},
Components = new OpenApiComponents() {
Schemas = new Dictionary<string, OpenApiSchema> {
{
"subNS.simpleObject", simpleObjet
}
}
},
};
var mockLogger = new Mock<ILogger<KiotaBuilder>>();
var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration() { ClientClassName = "Graph", ApiRootUrl = "https://localhost" });
var node = builder.CreateUriSpace(document);
var codeModel = builder.CreateSourceModel(node);
var requestBuilderNS = codeModel.FindNamespaceByName("ApiSdk.unionType");
Assert.NotNull(requestBuilderNS);
var requestBuilderClass = requestBuilderNS.FindChildByName<CodeClass>("unionTypeRequestBuilder", false);
Assert.NotNull(requestBuilderClass);
var requestExecutorMethod = requestBuilderClass.Methods.FirstOrDefault(x => x.IsOfKind(CodeMethodKind.RequestExecutor));
Assert.NotNull(requestExecutorMethod);
var executorReturnType = requestExecutorMethod.ReturnType as CodeUnionType;
Assert.NotNull(executorReturnType);
Assert.Equal(2, executorReturnType.Types.Count());
var typeNames = executorReturnType.Types.Select(x => x.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
Assert.Contains("simpleObject", typeNames);
Assert.Contains("number", typeNames);
}
[Fact]
public void UnionOfInlineSchemasWorks() {
var simpleObjet = new OpenApiSchema {
Type = "object",
Properties = new Dictionary<string, OpenApiSchema> {
{
"id", new OpenApiSchema {
Type = "string"
}
}
},
Reference = new OpenApiReference {
Id = "subNS.simpleObject",
Type = ReferenceType.Schema
},
UnresolvedReference = false
};
var document = new OpenApiDocument() {
Paths = new OpenApiPaths() {
["unionType"] = new OpenApiPathItem() {
Operations = {
[OperationType.Get] = new OpenApiOperation() {
Responses = new OpenApiResponses
{
["200"] = new OpenApiResponse {
Content = {
["application/json"] = new OpenApiMediaType {
Schema = new OpenApiSchema {
OneOf = new List<OpenApiSchema> {
simpleObjet,
new OpenApiSchema {
Type = "object",
Properties = new Dictionary<string, OpenApiSchema> {
{
"name", new OpenApiSchema {
Type = "string"
}
}
}
}
}
}
}
}
},
}
}
}
}
},
Components = new OpenApiComponents() {
Schemas = new Dictionary<string, OpenApiSchema> {
{
"subNS.simpleObject", simpleObjet
}
}
},
};
var mockLogger = new Mock<ILogger<KiotaBuilder>>();
var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration() { ClientClassName = "Graph", ApiRootUrl = "https://localhost" });
var node = builder.CreateUriSpace(document);
var codeModel = builder.CreateSourceModel(node);
var requestBuilderNS = codeModel.FindNamespaceByName("ApiSdk.unionType");
Assert.NotNull(requestBuilderNS);
var requestBuilderClass = requestBuilderNS.FindChildByName<CodeClass>("unionTypeRequestBuilder", false);
Assert.NotNull(requestBuilderClass);
var requestExecutorMethod = requestBuilderClass.Methods.FirstOrDefault(x => x.IsOfKind(CodeMethodKind.RequestExecutor));
Assert.NotNull(requestExecutorMethod);
var executorReturnType = requestExecutorMethod.ReturnType as CodeUnionType;
Assert.NotNull(executorReturnType);
Assert.Equal(2, executorReturnType.Types.Count());
var typeNames = executorReturnType.Types.Select(x => x.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
Assert.Contains("simpleObject", typeNames);
Assert.Contains("unionTypeResponseMember1", typeNames);
}
[InlineData("string", "", "string")]// https://spec.openapis.org/registry/format/
[InlineData("string", "commonmark", "string")]
[InlineData("string", "html", "string")]
Expand Down

0 comments on commit 7dd639e

Please sign in to comment.