From 6a7d4a531ab3a69c5a80557be532e205293baed0 Mon Sep 17 00:00:00 2001 From: 0marperez Date: Tue, 24 Sep 2024 13:44:26 -0400 Subject: [PATCH 1/8] Initial bug fix, no tests --- .../f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json | 5 +++++ .../codegen/rendering/PaginatorGenerator.kt | 19 +++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) create mode 100644 .changes/f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json diff --git a/.changes/f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json b/.changes/f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json new file mode 100644 index 000000000..23c3602fe --- /dev/null +++ b/.changes/f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json @@ -0,0 +1,5 @@ +{ + "id": "f71f083b-6e5f-4a3c-9069-464b1f9f6d36", + "type": "bugfix", + "description": "Fix paginator generator nullability unreliablity when collecting flows of collection types like map or list" +} \ No newline at end of file diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGenerator.kt index d96274492..adfcc6413 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGenerator.kt @@ -272,18 +272,21 @@ private fun getItemDescriptorOrNull(paginationInfo: PaginationInfo, ctx: Codegen val itemMember = ctx.model.expectShape(itemMemberId) val isSparse = itemMember.isSparse val (collectionLiteral, targetMember) = when (itemMember) { - is MapShape -> - ctx.symbolProvider.toSymbol(itemMember) - .expectProperty(SymbolProperty.ENTRY_EXPRESSION) as String to itemMember - is CollectionShape -> - ctx.symbolProvider.toSymbol(ctx.model.expectShape(itemMember.member.target)).name to ctx.model.expectShape( - itemMember.member.target, - ) + is MapShape -> { + val literal = ctx.symbolProvider.toSymbol(itemMember) + .expectProperty(SymbolProperty.ENTRY_EXPRESSION) as String + if (isSparse) "?" else "" + literal to itemMember + } + is CollectionShape -> { + val symbol = ctx.symbolProvider.toSymbol(ctx.model.expectShape(itemMember.member.target)) + val literal = symbol.name + if (symbol.isNullable || isSparse) "?" else "" + literal to ctx.model.expectShape(itemMember.member.target) + } else -> error("Unexpected shape type ${itemMember.type}") } return ItemDescriptor( - collectionLiteral + if (isSparse) "?" else "", + collectionLiteral, targetMember, itemLiteral, itemPathLiteral, From 9cb74f41f99f2b477c5c4170d9041d0c56d247c9 Mon Sep 17 00:00:00 2001 From: 0marperez <60363173+0marperez@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:47:56 -0400 Subject: [PATCH 2/8] Update f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json --- .changes/f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changes/f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json b/.changes/f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json index 23c3602fe..451569874 100644 --- a/.changes/f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json +++ b/.changes/f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json @@ -1,5 +1,5 @@ { "id": "f71f083b-6e5f-4a3c-9069-464b1f9f6d36", "type": "bugfix", - "description": "Fix paginator generator nullability unreliablity when collecting flows of collection types like map or list" -} \ No newline at end of file + "description": "Fix paginator generator `List` nullability" +} From d2a225ed2bcc2d617b9b5f65d37823bdca5d33ae Mon Sep 17 00:00:00 2001 From: 0marperez Date: Tue, 24 Sep 2024 20:29:50 -0400 Subject: [PATCH 3/8] Add paginator tests --- .../rendering/PaginatorGeneratorTest.kt | 304 ++++++++++++++++++ 1 file changed, 304 insertions(+) diff --git a/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGeneratorTest.kt b/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGeneratorTest.kt index 1c69df382..57d204369 100644 --- a/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGeneratorTest.kt +++ b/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGeneratorTest.kt @@ -762,4 +762,308 @@ class PaginatorGeneratorTest { actual.shouldContainOnlyOnceWithDiff(expected) } + + @Test + fun testRenderPaginatorWithDocumentList() { + val testModelWithItems = """ + namespace com.test + + use aws.protocols#restJson1 + + service Lambda { + operations: [ListFunctions] + } + + @paginated( + inputToken: "Marker", + outputToken: "NextMarker", + pageSize: "MaxItems", + items: "Functions" + ) + @readonly + @http(method: "GET", uri: "/functions", code: 200) + operation ListFunctions { + input: ListFunctionsRequest, + output: ListFunctionsResponse + } + + structure ListFunctionsRequest { + @httpQuery("FunctionVersion") + FunctionVersion: String, + @httpQuery("Marker") + Marker: String, + @httpQuery("MasterRegion") + MasterRegion: String, + @httpQuery("MaxItems") + MaxItems: Integer + } + + structure ListFunctionsResponse { + Functions: FunctionConfigurationList, + NextMarker: String + } + + list FunctionConfigurationList { + member: FunctionConfiguration + } + + document FunctionConfiguration + """.toSmithyModel() + val testContextWithItems = testModelWithItems.newTestContext("Lambda", "com.test") + + val codegenContextWithItems = object : CodegenContext { + override val model: Model = testContextWithItems.generationCtx.model + override val symbolProvider: SymbolProvider = testContextWithItems.generationCtx.symbolProvider + override val settings: KotlinSettings = testContextWithItems.generationCtx.settings + override val protocolGenerator: ProtocolGenerator = testContextWithItems.generator + override val integrations: List = testContextWithItems.generationCtx.integrations + } + + val unit = PaginatorGenerator() + unit.writeAdditionalFiles(codegenContextWithItems, testContextWithItems.generationCtx.delegator) + + testContextWithItems.generationCtx.delegator.flushWriters() + val testManifest = testContextWithItems.generationCtx.delegator.fileManifest as MockManifest + val actual = testManifest.expectFileString("src/main/kotlin/com/test/paginators/Paginators.kt") + + val expectedCode = """ + @JvmName("listFunctionsResponseFunctionConfiguration") + public fun Flow.functions(): Flow = + transform() { response -> + response.functions?.forEach { + emit(it) + } + } + """.trimIndent() + actual.shouldContainOnlyOnceWithDiff(expectedCode) + } + + @Test + fun testRenderPaginatorWithSparseDocumentList() { + val testModelWithItems = """ + namespace com.test + + use aws.protocols#restJson1 + + service Lambda { + operations: [ListFunctions] + } + + @paginated( + inputToken: "Marker", + outputToken: "NextMarker", + pageSize: "MaxItems", + items: "Functions" + ) + @readonly + @http(method: "GET", uri: "/functions", code: 200) + operation ListFunctions { + input: ListFunctionsRequest, + output: ListFunctionsResponse + } + + structure ListFunctionsRequest { + @httpQuery("FunctionVersion") + FunctionVersion: String, + @httpQuery("Marker") + Marker: String, + @httpQuery("MasterRegion") + MasterRegion: String, + @httpQuery("MaxItems") + MaxItems: Integer + } + + structure ListFunctionsResponse { + Functions: FunctionConfigurationList, + NextMarker: String + } + + @sparse + list FunctionConfigurationList { + member: FunctionConfiguration + } + + document FunctionConfiguration + """.toSmithyModel() + val testContextWithItems = testModelWithItems.newTestContext("Lambda", "com.test") + + val codegenContextWithItems = object : CodegenContext { + override val model: Model = testContextWithItems.generationCtx.model + override val symbolProvider: SymbolProvider = testContextWithItems.generationCtx.symbolProvider + override val settings: KotlinSettings = testContextWithItems.generationCtx.settings + override val protocolGenerator: ProtocolGenerator = testContextWithItems.generator + override val integrations: List = testContextWithItems.generationCtx.integrations + } + + val unit = PaginatorGenerator() + unit.writeAdditionalFiles(codegenContextWithItems, testContextWithItems.generationCtx.delegator) + + testContextWithItems.generationCtx.delegator.flushWriters() + val testManifest = testContextWithItems.generationCtx.delegator.fileManifest as MockManifest + val actual = testManifest.expectFileString("src/main/kotlin/com/test/paginators/Paginators.kt") + + val expectedCode = """ + @JvmName("listFunctionsResponseFunctionConfiguration") + public fun Flow.functions(): Flow = + transform() { response -> + response.functions?.forEach { + emit(it) + } + } + """.trimIndent() + actual.shouldContainOnlyOnceWithDiff(expectedCode) + } + + @Test + fun testRenderPaginatorWithDocumentMap() { + val testModelWithItems = """ + namespace com.test + + use aws.protocols#restJson1 + + service Lambda { + operations: [ListFunctions] + } + + @paginated( + inputToken: "Marker", + outputToken: "NextMarker", + pageSize: "MaxItems", + items: "Functions" + ) + @readonly + @http(method: "GET", uri: "/functions", code: 200) + operation ListFunctions { + input: ListFunctionsRequest, + output: ListFunctionsResponse + } + + structure ListFunctionsRequest { + @httpQuery("FunctionVersion") + FunctionVersion: String, + @httpQuery("Marker") + Marker: String, + @httpQuery("MasterRegion") + MasterRegion: String, + @httpQuery("MaxItems") + MaxItems: Integer + } + + structure ListFunctionsResponse { + Functions: FunctionConfigurationList, + NextMarker: String + } + + map FunctionConfigurationList { + key: String + value: FunctionConfiguration + } + + document FunctionConfiguration + """.toSmithyModel() + val testContextWithItems = testModelWithItems.newTestContext("Lambda", "com.test") + + val codegenContextWithItems = object : CodegenContext { + override val model: Model = testContextWithItems.generationCtx.model + override val symbolProvider: SymbolProvider = testContextWithItems.generationCtx.symbolProvider + override val settings: KotlinSettings = testContextWithItems.generationCtx.settings + override val protocolGenerator: ProtocolGenerator = testContextWithItems.generator + override val integrations: List = testContextWithItems.generationCtx.integrations + } + + val unit = PaginatorGenerator() + unit.writeAdditionalFiles(codegenContextWithItems, testContextWithItems.generationCtx.delegator) + + testContextWithItems.generationCtx.delegator.flushWriters() + val testManifest = testContextWithItems.generationCtx.delegator.fileManifest as MockManifest + val actual = testManifest.expectFileString("src/main/kotlin/com/test/paginators/Paginators.kt") + + val expectedCode = """ + @JvmName("listFunctionsResponseFunctionConfigurationList") + public fun Flow.functions(): Flow> = + transform() { response -> + response.functions?.forEach { + emit(it) + } + } + """.trimIndent() + actual.shouldContainOnlyOnceWithDiff(expectedCode) + } + + @Test + fun testRenderPaginatorWithSparseDocumentMap() { + val testModelWithItems = """ + namespace com.test + + use aws.protocols#restJson1 + + service Lambda { + operations: [ListFunctions] + } + + @paginated( + inputToken: "Marker", + outputToken: "NextMarker", + pageSize: "MaxItems", + items: "Functions" + ) + @readonly + @http(method: "GET", uri: "/functions", code: 200) + operation ListFunctions { + input: ListFunctionsRequest, + output: ListFunctionsResponse + } + + structure ListFunctionsRequest { + @httpQuery("FunctionVersion") + FunctionVersion: String, + @httpQuery("Marker") + Marker: String, + @httpQuery("MasterRegion") + MasterRegion: String, + @httpQuery("MaxItems") + MaxItems: Integer + } + + structure ListFunctionsResponse { + Functions: FunctionConfigurationList, + NextMarker: String + } + + @sparse + map FunctionConfigurationList { + key: String + value: FunctionConfiguration + } + + document FunctionConfiguration + """.toSmithyModel() + val testContextWithItems = testModelWithItems.newTestContext("Lambda", "com.test") + + val codegenContextWithItems = object : CodegenContext { + override val model: Model = testContextWithItems.generationCtx.model + override val symbolProvider: SymbolProvider = testContextWithItems.generationCtx.symbolProvider + override val settings: KotlinSettings = testContextWithItems.generationCtx.settings + override val protocolGenerator: ProtocolGenerator = testContextWithItems.generator + override val integrations: List = testContextWithItems.generationCtx.integrations + } + + val unit = PaginatorGenerator() + unit.writeAdditionalFiles(codegenContextWithItems, testContextWithItems.generationCtx.delegator) + + testContextWithItems.generationCtx.delegator.flushWriters() + val testManifest = testContextWithItems.generationCtx.delegator.fileManifest as MockManifest + val actual = testManifest.expectFileString("src/main/kotlin/com/test/paginators/Paginators.kt") + + val expectedCode = """ + @JvmName("listFunctionsResponseFunctionConfigurationList") + public fun Flow.functions(): Flow?> = + transform() { response -> + response.functions?.forEach { + emit(it) + } + } + """.trimIndent() + actual.shouldContainOnlyOnceWithDiff(expectedCode) + } } From 7344f7af0e53e4c195c1d536cb999fe9008d433c Mon Sep 17 00:00:00 2001 From: 0marperez Date: Wed, 25 Sep 2024 12:38:29 -0400 Subject: [PATCH 4/8] fix test naming, code duplication, clarity changes --- .../kotlin/codegen/rendering/PaginatorGenerator.kt | 11 ++++++----- .../codegen/rendering/PaginatorGeneratorTest.kt | 12 ++++++------ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGenerator.kt index adfcc6413..922232b6f 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGenerator.kt @@ -273,14 +273,15 @@ private fun getItemDescriptorOrNull(paginationInfo: PaginationInfo, ctx: Codegen val isSparse = itemMember.isSparse val (collectionLiteral, targetMember) = when (itemMember) { is MapShape -> { - val literal = ctx.symbolProvider.toSymbol(itemMember) - .expectProperty(SymbolProperty.ENTRY_EXPRESSION) as String + if (isSparse) "?" else "" - literal to itemMember + val symbol = ctx.symbolProvider.toSymbol(itemMember) + val entryExpression = symbol.expectProperty(SymbolProperty.ENTRY_EXPRESSION) as String + if (isSparse) "?" else "" + entryExpression to itemMember } is CollectionShape -> { - val symbol = ctx.symbolProvider.toSymbol(ctx.model.expectShape(itemMember.member.target)) + val target = ctx.model.expectShape(itemMember.member.target) + val symbol = ctx.symbolProvider.toSymbol(target) val literal = symbol.name + if (symbol.isNullable || isSparse) "?" else "" - literal to ctx.model.expectShape(itemMember.member.target) + literal to target } else -> error("Unexpected shape type ${itemMember.type}") } diff --git a/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGeneratorTest.kt b/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGeneratorTest.kt index 57d204369..465b36751 100644 --- a/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGeneratorTest.kt +++ b/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGeneratorTest.kt @@ -950,11 +950,11 @@ class PaginatorGeneratorTest { } structure ListFunctionsResponse { - Functions: FunctionConfigurationList, + Functions: FunctionConfigurationMap, NextMarker: String } - map FunctionConfigurationList { + map FunctionConfigurationMap { key: String value: FunctionConfiguration } @@ -979,7 +979,7 @@ class PaginatorGeneratorTest { val actual = testManifest.expectFileString("src/main/kotlin/com/test/paginators/Paginators.kt") val expectedCode = """ - @JvmName("listFunctionsResponseFunctionConfigurationList") + @JvmName("listFunctionsResponseFunctionConfigurationMap") public fun Flow.functions(): Flow> = transform() { response -> response.functions?.forEach { @@ -1026,12 +1026,12 @@ class PaginatorGeneratorTest { } structure ListFunctionsResponse { - Functions: FunctionConfigurationList, + Functions: FunctionConfigurationMap, NextMarker: String } @sparse - map FunctionConfigurationList { + map FunctionConfigurationMap { key: String value: FunctionConfiguration } @@ -1056,7 +1056,7 @@ class PaginatorGeneratorTest { val actual = testManifest.expectFileString("src/main/kotlin/com/test/paginators/Paginators.kt") val expectedCode = """ - @JvmName("listFunctionsResponseFunctionConfigurationList") + @JvmName("listFunctionsResponseFunctionConfigurationMap") public fun Flow.functions(): Flow?> = transform() { response -> response.functions?.forEach { From ced4b0a1388df656fa0e14a1d771be5167336d6b Mon Sep 17 00:00:00 2001 From: 0marperez Date: Wed, 25 Sep 2024 12:39:04 -0400 Subject: [PATCH 5/8] update changelog --- .changes/f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changes/f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json b/.changes/f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json index 451569874..980b2c26a 100644 --- a/.changes/f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json +++ b/.changes/f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json @@ -1,5 +1,5 @@ { "id": "f71f083b-6e5f-4a3c-9069-464b1f9f6d36", "type": "bugfix", - "description": "Fix paginator generator `List` nullability" + "description": "Fix paginator generator `List<*>` nullability" } From 73cc2bbe6074c536015ddb3f52d4aee4630505f5 Mon Sep 17 00:00:00 2001 From: 0marperez Date: Thu, 26 Sep 2024 15:46:00 -0400 Subject: [PATCH 6/8] Fix sparse map codegen as well --- .../codegen/core/KotlinSymbolProvider.kt | 2 +- .../codegen/rendering/PaginatorGenerator.kt | 2 +- .../rendering/PaginatorGeneratorTest.kt | 79 ++++++++++++++++++- 3 files changed, 80 insertions(+), 3 deletions(-) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/KotlinSymbolProvider.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/KotlinSymbolProvider.kt index 1f7eb9408..e6dbd0dca 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/KotlinSymbolProvider.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/KotlinSymbolProvider.kt @@ -166,7 +166,7 @@ class KotlinSymbolProvider(private val model: Model, private val settings: Kotli val fullyQualifiedKeyType = keyReference.fullName val valueReference = toSymbol(shape.value) - val valueSuffix = if (valueReference.isNullable) "?" else "" + val valueSuffix = if (valueReference.isNullable || shape.isSparse) "?" else "" val valueType = "${valueReference.name}$valueSuffix" val fullyQualifiedValueType = "${valueReference.fullName}$valueSuffix" diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGenerator.kt index 922232b6f..7ac76fee7 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGenerator.kt @@ -274,7 +274,7 @@ private fun getItemDescriptorOrNull(paginationInfo: PaginationInfo, ctx: Codegen val (collectionLiteral, targetMember) = when (itemMember) { is MapShape -> { val symbol = ctx.symbolProvider.toSymbol(itemMember) - val entryExpression = symbol.expectProperty(SymbolProperty.ENTRY_EXPRESSION) as String + if (isSparse) "?" else "" + val entryExpression = symbol.expectProperty(SymbolProperty.ENTRY_EXPRESSION) as String entryExpression to itemMember } is CollectionShape -> { diff --git a/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGeneratorTest.kt b/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGeneratorTest.kt index 465b36751..0dafcdb9c 100644 --- a/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGeneratorTest.kt +++ b/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGeneratorTest.kt @@ -1057,7 +1057,84 @@ class PaginatorGeneratorTest { val expectedCode = """ @JvmName("listFunctionsResponseFunctionConfigurationMap") - public fun Flow.functions(): Flow?> = + public fun Flow.functions(): Flow> = + transform() { response -> + response.functions?.forEach { + emit(it) + } + } + """.trimIndent() + actual.shouldContainOnlyOnceWithDiff(expectedCode) + } + + @Test + fun testRenderPaginatorWithSparseStringMap() { + val testModelWithItems = """ + namespace com.test + + use aws.protocols#restJson1 + + service Lambda { + operations: [ListFunctions] + } + + @paginated( + inputToken: "Marker", + outputToken: "NextMarker", + pageSize: "MaxItems", + items: "Functions" + ) + @readonly + @http(method: "GET", uri: "/functions", code: 200) + operation ListFunctions { + input: ListFunctionsRequest, + output: ListFunctionsResponse + } + + structure ListFunctionsRequest { + @httpQuery("FunctionVersion") + FunctionVersion: String, + @httpQuery("Marker") + Marker: String, + @httpQuery("MasterRegion") + MasterRegion: String, + @httpQuery("MaxItems") + MaxItems: Integer + } + + structure ListFunctionsResponse { + Functions: FunctionConfigurationMap, + NextMarker: String + } + + @sparse + map FunctionConfigurationMap { + key: String + value: FunctionConfiguration + } + + string FunctionConfiguration + """.toSmithyModel() + val testContextWithItems = testModelWithItems.newTestContext("Lambda", "com.test") + + val codegenContextWithItems = object : CodegenContext { + override val model: Model = testContextWithItems.generationCtx.model + override val symbolProvider: SymbolProvider = testContextWithItems.generationCtx.symbolProvider + override val settings: KotlinSettings = testContextWithItems.generationCtx.settings + override val protocolGenerator: ProtocolGenerator = testContextWithItems.generator + override val integrations: List = testContextWithItems.generationCtx.integrations + } + + val unit = PaginatorGenerator() + unit.writeAdditionalFiles(codegenContextWithItems, testContextWithItems.generationCtx.delegator) + + testContextWithItems.generationCtx.delegator.flushWriters() + val testManifest = testContextWithItems.generationCtx.delegator.fileManifest as MockManifest + val actual = testManifest.expectFileString("src/main/kotlin/com/test/paginators/Paginators.kt") + + val expectedCode = """ + @JvmName("listFunctionsResponseFunctionConfigurationMap") + public fun Flow.functions(): Flow> = transform() { response -> response.functions?.forEach { emit(it) From cd3ae1bf87df6f569c40e870663107dd03db19b6 Mon Sep 17 00:00:00 2001 From: 0marperez Date: Thu, 26 Sep 2024 15:53:53 -0400 Subject: [PATCH 7/8] update changelog --- .changes/f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changes/f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json b/.changes/f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json index 980b2c26a..0055ce0ac 100644 --- a/.changes/f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json +++ b/.changes/f71f083b-6e5f-4a3c-9069-464b1f9f6d36.json @@ -1,5 +1,5 @@ { "id": "f71f083b-6e5f-4a3c-9069-464b1f9f6d36", "type": "bugfix", - "description": "Fix paginator generator `List<*>` nullability" + "description": "Fix paginator generator `List<*>` & `Map.Entry` nullability" } From 487d1fc026405ef5fdba1b789bb26bb19f0caa27 Mon Sep 17 00:00:00 2001 From: 0marperez Date: Thu, 26 Sep 2024 17:09:54 -0400 Subject: [PATCH 8/8] Add non sparse map test --- .../rendering/PaginatorGeneratorTest.kt | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGeneratorTest.kt b/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGeneratorTest.kt index 0dafcdb9c..7b08a6d86 100644 --- a/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGeneratorTest.kt +++ b/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/PaginatorGeneratorTest.kt @@ -1143,4 +1143,80 @@ class PaginatorGeneratorTest { """.trimIndent() actual.shouldContainOnlyOnceWithDiff(expectedCode) } + + @Test + fun testRenderPaginatorWithStringMap() { + val testModelWithItems = """ + namespace com.test + + use aws.protocols#restJson1 + + service Lambda { + operations: [ListFunctions] + } + + @paginated( + inputToken: "Marker", + outputToken: "NextMarker", + pageSize: "MaxItems", + items: "Functions" + ) + @readonly + @http(method: "GET", uri: "/functions", code: 200) + operation ListFunctions { + input: ListFunctionsRequest, + output: ListFunctionsResponse + } + + structure ListFunctionsRequest { + @httpQuery("FunctionVersion") + FunctionVersion: String, + @httpQuery("Marker") + Marker: String, + @httpQuery("MasterRegion") + MasterRegion: String, + @httpQuery("MaxItems") + MaxItems: Integer + } + + structure ListFunctionsResponse { + Functions: FunctionConfigurationMap, + NextMarker: String + } + + map FunctionConfigurationMap { + key: String + value: FunctionConfiguration + } + + string FunctionConfiguration + """.toSmithyModel() + val testContextWithItems = testModelWithItems.newTestContext("Lambda", "com.test") + + val codegenContextWithItems = object : CodegenContext { + override val model: Model = testContextWithItems.generationCtx.model + override val symbolProvider: SymbolProvider = testContextWithItems.generationCtx.symbolProvider + override val settings: KotlinSettings = testContextWithItems.generationCtx.settings + override val protocolGenerator: ProtocolGenerator = testContextWithItems.generator + override val integrations: List = testContextWithItems.generationCtx.integrations + } + + val unit = PaginatorGenerator() + unit.writeAdditionalFiles(codegenContextWithItems, testContextWithItems.generationCtx.delegator) + + testContextWithItems.generationCtx.delegator.flushWriters() + val testManifest = testContextWithItems.generationCtx.delegator.fileManifest as MockManifest + val actual = testManifest.expectFileString("src/main/kotlin/com/test/paginators/Paginators.kt") + + val expectedCode = """ + @JvmName("listFunctionsResponseFunctionConfigurationMap") + public fun Flow.functions(): Flow> = + transform() { response -> + response.functions?.forEach { + emit(it) + } + } + """.trimIndent() + actual.shouldContainOnlyOnceWithDiff(expectedCode) + } }