Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update Jmespath shape traversal codegen to support multi-select lists…
… following projection expressions (#3987) ## Motivation and Context Adds support for JMESPath multi-select lists following projection expressions such as `lists.structs[].[optionalInt, requiredInt]` (list projection followed by multi-select lists), `lists.structs[<some filter condition>].[optionalInt, requiredInt]` (filter projection followed by multi-select lists), and `maps.*.[optionalInt, requiredInt]` (object projection followed by multi-select lists). ## Description This PR adds support for the said functionality. Prior to the PR, the expressions above ended up the codegen either failing to generate code (for list projection) or generating the incorrect Rust code (for filter & object projection). All the code changes except for `RustJmespathShapeTraversalGenerator.kt` are primarily adjusting the existing code based on the updates made to `RustJmespathShapeTraversalGenerator.kt`. The gist of the code changes in `RustJmespathShapeTraversalGenerator.kt` is as follows: - `generateProjection` now supports `MultiSelectListExpression` on the right-hand side (RHS). - Previously, given `MultiSelectListExpression` on RHS, the `map` function applied to the result of the left-hand side of a projection expression (regardless of whether it's list, filter, or object projection) returned a type `Option<Vec<&T>>`, and the `map` function body used the `?` operator to return early as soon as it encountered a field value that was `None`. That did not yield the desired behavior. Given the snippet `lists.structs[].[optionalInt, requiredInt]` in the `Motivation and Context` above for instance, the `map` function used to look like this: ``` fn map(_v: &crate::types::Struct) -> Option<Vec<&i32>> { let _fld_1 = _v.optional_int.as_ref()?; let _fld_2 = _v.required_int; let _msl = vec![_fld_1, _fld_2]; Some(_msl) ``` This meant if the `optional_int` in a `Struct` was `None`, we lost the chance to access the `required_int` field when we should've. Instead, the `map` function now looks like: ``` fn map(_v: &crate::types::Struct) -> Option<Vec<Option<&i32>>> { let _fld_1 = _v.optional_int.as_ref(); let _fld_2 = Some(_v.required_int); let _msl = vec![_fld_1, _fld_2]; Some(_msl) ``` This way, the `map` function body has a chance to access all the fields of `Struct` even when any of the optional fields in a `Struct` is `None`. - Given the update to the signature of the `map` function above, `generate*Projection` functions have adjusted their implementations (such as [preserving the output type of the whole projection expression](https://github.com/smithy-lang/smithy-rs/blob/01fed784d5fc2ef6743a336496d91a51f01e6ab2/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/waiters/RustJmespathShapeTraversalGenerator.kt#L989-L1010) and performing [additional flattening for `Option`s](https://github.com/smithy-lang/smithy-rs/blob/01fed784d5fc2ef6743a336496d91a51f01e6ab2/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/waiters/RustJmespathShapeTraversalGenerator.kt#L757-L760)). Note that the output type of the whole projection expression stays the same before and after this PR; it's just that the inner `map` function used by the projection expression has been tweaked. ## Testing - Confirmed existing tests continued working (CI and release pipeline). - Added additional JMESPath codegen tests in `RustJmespathShapeTraversalGeneratorTest.kt`. - Confirmed that the updated service model with a JMESPath expression like `Items[*].[A.Name, B.Name, C.Name, D.Name][]` generated the expected Rust code and behaved as expected. ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._
- Loading branch information