Skip to content

Commit

Permalink
Render response models breadth-first (#5802)
Browse files Browse the repository at this point in the history
Render response models breadth-first
  • Loading branch information
heaths authored Mar 27, 2023
1 parent 020dbc9 commit cc94822
Show file tree
Hide file tree
Showing 3 changed files with 238 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public bool IsPropertyRequired(string propertyName)
[JsonPropertyName("$ref")] public string Ref { get; set; }

private List<SchemaTableItem> tableItems;
private Queue<(BaseSchema, SerializeContext)> propertyQueue = new();


public bool IsRefObj()
Expand Down Expand Up @@ -158,6 +159,7 @@ private CodeFileToken[] TokenSerializeInternal(SerializeContext context, BaseSch

if (schema.properties?.Count != 0)
{
// BUGBUG: Herein lies the problem. We're recursing down into child objects when we should be queuing them instead.
TokenSerializeProperties(context, schema, schema.properties, ret, ref flattenedTableItems, serializeRef);
}

Expand Down Expand Up @@ -203,6 +205,13 @@ private CodeFileToken[] TokenSerializeInternal(SerializeContext context, BaseSch
}
}

// Now recurse into nested model definitions so all properties are grouped with their models.
while (this.propertyQueue.TryDequeue(out var property))
{
var (item, childContext) = property;
ret.AddRange(item.TokenSerializeInternal(childContext, item, ref flattenedTableItems, serializeRef));
}

return ret.ToArray();
}

Expand All @@ -222,7 +231,7 @@ private static List<string> GetPropertyKeywordsFromBaseSchema(BaseSchema baseSch
return keywords.ToList();
}

private static void TokenSerializeProperties(SerializeContext context, BaseSchema schema, Dictionary<string, BaseSchema> properties, List<CodeFileToken> ret, ref List<SchemaTableItem> flattenedTableItems,
private void TokenSerializeProperties(SerializeContext context, BaseSchema schema, Dictionary<string, BaseSchema> properties, List<CodeFileToken> ret, ref List<SchemaTableItem> flattenedTableItems,
Boolean serializeRef = true)
{
if (properties == null)
Expand All @@ -248,7 +257,7 @@ private static void TokenSerializeProperties(SerializeContext context, BaseSchem
ret.Add(TokenSerializer.NewLine());
if (serializeRef)
{
ret.AddRange(schema.TokenSerializeInternal(new SerializeContext(context.intent + 1, context.IteratorPath), kv.Value, ref flattenedTableItems, serializeRef));
this.propertyQueue.Enqueue((kv.Value, new SerializeContext(context.intent + 1, context.IteratorPath)));
}
}
// Circular reference case: the ref won't be expanded.
Expand Down Expand Up @@ -291,7 +300,7 @@ private static void TokenSerializeProperties(SerializeContext context, BaseSchem
}
}

private static void TokenSerializeArray(SerializeContext context, List<CodeFileToken> ret, BaseSchema arraySchema, ref List<SchemaTableItem> flattenedTableItems, Boolean serializeRef)
private void TokenSerializeArray(SerializeContext context, List<CodeFileToken> ret, BaseSchema arraySchema, ref List<SchemaTableItem> flattenedTableItems, Boolean serializeRef)
{
ret.Add(new CodeFileToken("array", CodeFileTokenKind.Keyword));
if (arraySchema.items == null)
Expand Down Expand Up @@ -322,7 +331,7 @@ private static void TokenSerializeArray(SerializeContext context, List<CodeFileT

if (serializeRef)
{
ret.AddRange(arraySchema.items.TokenSerializeInternal(new SerializeContext(context.intent + 1, context.IteratorPath), arraySchema.items, ref flattenedTableItems, serializeRef));
this.propertyQueue.Enqueue((arraySchema.items, new SerializeContext(context.intent + 1, context.IteratorPath)));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using SwaggerApiParser;
using Xunit;
Expand Down Expand Up @@ -55,4 +58,26 @@ public async Task TestGenerateSwaggerApiViewCompute()
await using FileStream writer = File.Open(outputFilePath, FileMode.Create);
await codeFile.SerializeAsync(writer);*/
}

[Fact]
public async Task TestGenerateSwaggerApiViewGroupedModelProperties()
{
var runCommandsFilePath = Path.GetFullPath("./fixtures/communicationserviceschat.json");
var swaggerSpec = await SwaggerDeserializer.Deserialize(runCommandsFilePath);
var apiView = SwaggerApiViewGenerator.GenerateSwaggerApiView(swaggerSpec, runCommandsFilePath, new SchemaCache());

var codeFile = apiView.GenerateCodeFile();
//var outputFilePath = Path.GetFullPath("./communicationserviceschat_output.json");

//this.output.WriteLine($"Write result to: {outputFilePath}");
//await using var writer = File.Open(outputFilePath, FileMode.Create);
//await codeFile.SerializeAsync(writer);

var elems = codeFile.Tokens
.Select((item, index) => (item, index))
.SkipWhile(elem => elem.item.Value != "200")
.Where(elem => elem.item.Value == "nextLink" || elem.item.Value == "retentionPolicy")
.Take(2);
Assert.Collection(elems, elem => Assert.Equal("nextLink", elem.item.Value), elem => Assert.Equal("retentionPolicy", elem.item.Value));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
{
"swagger": "2.0",
"info": {
"title": "Azure Communication Chat Service",
"description": "Azure Communication Chat Service",
"version": "2023-07-01-preview"
},
"paths": {
"/chat/threads": {
"get": {
"tags": [
"Threads"
],
"summary": "Gets the list of chat threads of a user.",
"operationId": "Chat_ListChatThreads",
"produces": [
"application/json"
],
"parameters": [
{
"in": "query",
"name": "maxPageSize",
"description": "The maximum number of chat threads returned per page.",
"type": "integer",
"format": "int32"
},
{
"in": "query",
"name": "startTime",
"description": "The earliest point in time to get chat threads up to. The timestamp should be in RFC3339 format: `yyyy-MM-ddTHH:mm:ssZ`.",
"type": "string",
"format": "date-time"
},
{
"$ref": "#/parameters/ApiVersionParameter"
}
],
"responses": {
"200": {
"description": "Request successful. The action returns a `GetThreadsResponse` resource.",
"schema": {
"$ref": "#/definitions/ChatThreadsItemCollection"
}
}
},
"x-ms-pageable": {
"nextLinkName": "nextLink",
"itemName": "value"
}
}
}
},
"definitions": {
"ChatThreadItem": {
"description": "Summary information of a chat thread.",
"required": [
"id",
"topic"
],
"type": "object",
"properties": {
"id": {
"description": "Chat thread id.",
"type": "string",
"example": "19:uni01_uy5ucb66ugp3lrhe7pxso6xx4hsmm3dl6eyjfefv2n6x3rrurpea@thread.v2"
},
"topic": {
"description": "Chat thread topic.",
"type": "string",
"example": "Lunch Chat thread"
},
"deletedOn": {
"format": "date-time",
"description": "The timestamp when the chat thread was deleted. The timestamp is in RFC3339 format: `yyyy-MM-ddTHH:mm:ssZ`.",
"type": "string",
"example": "2020-10-30T10:50:50Z"
},
"lastMessageReceivedOn": {
"format": "date-time",
"description": "The timestamp when the last message arrived at the server. The timestamp is in RFC3339 format: `yyyy-MM-ddTHH:mm:ssZ`.",
"type": "string",
"readOnly": true,
"example": "2020-10-30T10:50:50Z"
},
"retentionPolicy": {
"$ref": "#/definitions/RetentionPolicy"
}
}
},
"ChatThreadsItemCollection": {
"description": "Collection of chat threads.",
"required": [
"value"
],
"type": "object",
"properties": {
"value": {
"description": "Collection of chat threads.",
"type": "array",
"items": {
"$ref": "#/definitions/ChatThreadItem"
}
},
"nextLink": {
"description": "If there are more chat threads that can be retrieved, the next link will be populated.",
"type": "string",
"readOnly": true
}
}
},
"RetentionPolicy": {
"description": "Data retention policy for auto deletion.",
"type": "object",
"discriminator": "policyType",
"properties": {
"policyType": {
"description": "Retention Policy Type",
"enum": [
"basedOnThreadCreationDate"
],
"type": "string",
"x-ms-enum": {
"name": "policyType",
"modelAsString": true,
"values": [
{
"value": "basedOnThreadCreationDate",
"description": "Thread retention policy based on thread creation date."
}
]
}
}
},
"required": [
"policyType"
]
},
"BasedOnThreadCreationDateRetentionPolicy": {
"description": "Thread retention policy based on thread creation date.",
"type": "object",
"x-ms-discriminator-value": "basedOnThreadCreationDate",
"allOf": [
{
"$ref": "#/definitions/RetentionPolicy"
}
],
"properties": {
"daysAfterCreation": {
"type": "integer",
"format": "int32",
"description": "Indicates how many days after the thread creation the thread will be deleted. Only 90 is accepted for now."
}
},
"required": [
"daysAfterCreation"
]
}
},
"parameters": {
"ApiVersionParameter": {
"in": "query",
"name": "api-version",
"description": "Version of API to invoke.",
"required": true,
"type": "string",
"x-ms-parameter-location": "method"
},
"Endpoint": {
"in": "path",
"name": "endpoint",
"description": "The endpoint of the Azure Communication resource.",
"required": true,
"type": "string",
"x-ms-skip-url-encoding": true,
"x-ms-parameter-location": "client"
}
},
"securityDefinitions": {
"Authorization": {
"type": "apiKey",
"name": "Authorization",
"in": "header",
"description": "An ACS (Azure Communication Services) user access token."
}
},
"security": [
{
"Authorization": []
}
],
"x-ms-parameterized-host": {
"hostTemplate": "{endpoint}",
"useSchemePrefix": false,
"parameters": [
{
"$ref": "#/parameters/Endpoint"
}
]
}
}

0 comments on commit cc94822

Please sign in to comment.