Skip to content
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

fix: paginator generator nullability bug caused by documents #1155

Merged
merged 9 commits into from
Sep 27, 2024

Conversation

0marperez
Copy link
Contributor

@0marperez 0marperez commented Sep 24, 2024

Issue #

The paginator generator is not code-generating nullable literals for item paginators of lists that have values that are nullable. It will only code-generate nullability if the list is marked as sparse and not check if the list has values that are nullable.

Lists are not supposed to contain nullable items unless marked as sparse, so this is non-modeled behavior that we were not looking for but is necessary because documents are always nullable in smithy kotlin.

Description of changes

The paginator generator now checks if the collection is made of nullable symbols and code generates nullability

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

This comment has been minimized.

@0marperez 0marperez changed the title fix: paginator generator item paginator nullability bug fix: paginator generator item paginator nullability bug caused by documents Sep 24, 2024
@0marperez 0marperez marked this pull request as ready for review September 24, 2024 18:40
@0marperez 0marperez requested a review from a team as a code owner September 24, 2024 18:40
@0marperez 0marperez changed the title fix: paginator generator item paginator nullability bug caused by documents fix: paginator generator nullability bug caused by documents Sep 24, 2024

This comment has been minimized.

Copy link
Contributor

@ianbotsf ianbotsf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: Missing test coverage. Add unit tests as a minimum and preferably codegen tests as well.

Comment on lines 275 to 279
is MapShape -> {
val literal = ctx.symbolProvider.toSymbol(itemMember)
.expectProperty(SymbolProperty.ENTRY_EXPRESSION) as String + if (isSparse) "?" else ""
literal to itemMember
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Don't we also need to check if the symbol is nullable alongside the map being sparse?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify a little bit? I'm confused why MapShape only checks isSparse while CollectionShape checks symbol.isNullable || isSparse

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, for MapShape the symbol provider provides the symbol via toSymbol and then we use the ENTRY_EXPRESSION system property from the symbol as the literal, and never look at the type that the map targets like in collections.

The ENTRY_EXPRESSION system property is set in the code I linked above. It uses val valueType which uses val valueSuffix to add the ? is the value is nullable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that's what we want. Your new unit test testRenderPaginatorWithSparseDocumentMap shows the problem: It takes a sparse map shape with Document values and codegens a paginator that returns Flow<Map.Entry<String, Document?>?>.

Note that there are two nullability modifiers:

  • one on Document because Document is nullable, which is correct
  • one on Map.Entry<String, Document?> because the map is sparse, which is incorrect

A sparse map does not have missing entries, only missing values. I believe the logic needs to coalesce the Document nullability and the map sparseness into the same spot. In other words, I believe the testRenderPaginatorWithSparseDocumentMap test should be expecting a Flow<Map.Entry<String, Document?>>.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that too, we've been code-generating them like that so I wasn't 100% sure if it was wrong. The fix is in the PR now.

@0marperez
Copy link
Contributor Author

Yeah, this was my mistake I marked as ready for review before adding the tests!

This comment has been minimized.

literal to itemMember
}
is CollectionShape -> {
val symbol = ctx.symbolProvider.toSymbol(ctx.model.expectShape(itemMember.member.target))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

simplification/duplication: ctx.model.expectShape(itemMember.member.target) is used twice, refactor to local value

{
"id": "f71f083b-6e5f-4a3c-9069-464b1f9f6d36",
"type": "bugfix",
"description": "Fix paginator generator `List<Document>` nullability"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit/clarification: This change does not only affect List<Document>, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should only affect List<Document> types because they're the only type of list that can contain nullables without the sparse trait being set on the list. Looking at KotlinSymbolProvider, document is the only symbol that always returns asNullable()

NextMarker: String
}

map FunctionConfigurationList {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

naming: This is a map

Comment on lines 275 to 279
is MapShape -> {
val literal = ctx.symbolProvider.toSymbol(itemMember)
.expectProperty(SymbolProperty.ENTRY_EXPRESSION) as String + if (isSparse) "?" else ""
literal to itemMember
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify a little bit? I'm confused why MapShape only checks isSparse while CollectionShape checks symbol.isNullable || isSparse

This comment has been minimized.

Comment on lines +766 to +767
@Test
fun testRenderPaginatorWithDocumentList() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Let add a comment to each linking the issue that spawned them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll create one, we don't have an external issue for this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh maybe not required if there wasn't an external issue...that's just busywork.

Comment on lines 275 to 279
is MapShape -> {
val literal = ctx.symbolProvider.toSymbol(itemMember)
.expectProperty(SymbolProperty.ENTRY_EXPRESSION) as String + if (isSparse) "?" else ""
literal to itemMember
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that's what we want. Your new unit test testRenderPaginatorWithSparseDocumentMap shows the problem: It takes a sparse map shape with Document values and codegens a paginator that returns Flow<Map.Entry<String, Document?>?>.

Note that there are two nullability modifiers:

  • one on Document because Document is nullable, which is correct
  • one on Map.Entry<String, Document?> because the map is sparse, which is incorrect

A sparse map does not have missing entries, only missing values. I believe the logic needs to coalesce the Document nullability and the map sparseness into the same spot. In other words, I believe the testRenderPaginatorWithSparseDocumentMap test should be expecting a Flow<Map.Entry<String, Document?>>.

This comment has been minimized.

This comment has been minimized.

Copy link

Affected Artifacts

No artifacts changed size

@0marperez 0marperez merged commit 630fbf2 into main Sep 27, 2024
15 checks passed
@0marperez 0marperez deleted the document-nullability branch September 27, 2024 17:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants