-
Notifications
You must be signed in to change notification settings - Fork 30
fix: correctly codegen paginators for types which require fully-qualified names #1249
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| "id": "13a47747-197a-4b88-bc3b-393af5f5127a", | ||
| "type": "bugfix", | ||
| "description": "Correctly generate paginators for item type names which collide with other used types (e.g., an item type `com.foo.Flow` which conflicts with `kotlinx.coroutines.flow.Flow`)" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -263,6 +263,130 @@ class PaginatorGeneratorTest { | |
| actual.shouldContainOnlyOnceWithDiff(expectedImports) | ||
| } | ||
|
|
||
| @Test | ||
| fun testRenderPaginatorWithItemRequiringFqName() { | ||
| val testModelWithItems = """ | ||
| namespace com.test | ||
|
|
||
| use aws.protocols#restJson1 | ||
|
|
||
| service FlowService { | ||
| operations: [ListFlows] | ||
| } | ||
|
|
||
| @paginated( | ||
| inputToken: "Marker", | ||
| outputToken: "NextMarker", | ||
| pageSize: "MaxItems", | ||
| items: "Flows" | ||
| ) | ||
| @readonly | ||
| @http(method: "GET", uri: "/flows", code: 200) | ||
| operation ListFlows { | ||
| input: ListFlowsRequest, | ||
| output: ListFlowsResponse | ||
| } | ||
|
|
||
| structure ListFlowsRequest { | ||
| @httpQuery("FlowVersion") | ||
| FlowVersion: String, | ||
| @httpQuery("Marker") | ||
| Marker: String, | ||
| @httpQuery("MasterRegion") | ||
| MasterRegion: String, | ||
| @httpQuery("MaxItems") | ||
| MaxItems: Integer | ||
| } | ||
|
|
||
| structure ListFlowsResponse { | ||
| Flows: FlowList, | ||
| NextMarker: String | ||
| } | ||
|
|
||
| list FlowList { | ||
| member: Flow | ||
| } | ||
|
|
||
| structure Flow { | ||
| Name: String | ||
| } | ||
| """.toSmithyModel() | ||
| val testContextWithItems = testModelWithItems.newTestContext("FlowService", "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<KotlinIntegration> = 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 = """ | ||
| /** | ||
| * Paginate over [ListFlowsResponse] results. | ||
| * | ||
| * When this operation is called, a [kotlinx.coroutines.Flow] is created. Flows are lazy (cold) so no service | ||
| * calls are made until the flow is collected. This also means there is no guarantee that the request is valid | ||
| * until then. Once you start collecting the flow, the SDK will lazily load response pages by making service | ||
| * calls until there are no pages left or the flow is cancelled. If there are errors in your request, you will | ||
| * see the failures only after you start collection. | ||
| * @param initialRequest A [ListFlowsRequest] to start pagination | ||
| * @return A [kotlinx.coroutines.flow.Flow] that can collect [ListFlowsResponse] | ||
| */ | ||
| public fun TestClient.listFlowsPaginated(initialRequest: ListFlowsRequest = ListFlowsRequest { }): kotlinx.coroutines.flow.Flow<ListFlowsResponse> = | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: These will only be fully qualified
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, although typically |
||
| flow { | ||
| var cursor: kotlin.String? = initialRequest.marker | ||
| var hasNextPage: Boolean = true | ||
|
|
||
| while (hasNextPage) { | ||
| val req = initialRequest.copy { | ||
| this.marker = cursor | ||
| } | ||
| val result = [email protected](req) | ||
| cursor = result.nextMarker | ||
| hasNextPage = cursor?.isNotEmpty() == true | ||
| emit(result) | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Paginate over [ListFlowsResponse] results. | ||
| * | ||
| * When this operation is called, a [kotlinx.coroutines.Flow] is created. Flows are lazy (cold) so no service | ||
| * calls are made until the flow is collected. This also means there is no guarantee that the request is valid | ||
| * until then. Once you start collecting the flow, the SDK will lazily load response pages by making service | ||
| * calls until there are no pages left or the flow is cancelled. If there are errors in your request, you will | ||
| * see the failures only after you start collection. | ||
| * @param block A builder block used for DSL-style invocation of the operation | ||
| * @return A [kotlinx.coroutines.flow.Flow] that can collect [ListFlowsResponse] | ||
| */ | ||
| public fun TestClient.listFlowsPaginated(block: ListFlowsRequest.Builder.() -> Unit): kotlinx.coroutines.flow.Flow<ListFlowsResponse> = | ||
| listFlowsPaginated(ListFlowsRequest.Builder().apply(block).build()) | ||
|
|
||
| /** | ||
| * This paginator transforms the flow returned by [listFlowsPaginated] | ||
| * to access the nested member [Flow] | ||
| * @return A [kotlinx.coroutines.flow.Flow] that can collect [Flow] | ||
| */ | ||
| @JvmName("listFlowsResponseFlow") | ||
| public fun kotlinx.coroutines.flow.Flow<ListFlowsResponse>.flows(): kotlinx.coroutines.flow.Flow<Flow> = | ||
| transform() { response -> | ||
| response.flows?.forEach { | ||
| emit(it) | ||
| } | ||
| } | ||
| """.trimIndent() | ||
|
|
||
| actual.shouldContainOnlyOnceWithDiff(expectedCode) | ||
| } | ||
|
|
||
| @Test | ||
| fun testRenderPaginatorWithSparseItem() { | ||
| val testModelWithItems = """ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion:
Fq->FullyQualifiedThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about just
Fullinstead?