Skip to content
Unverified Commit dae6b264 authored by ysaito1001's avatar ysaito1001 Committed by GitHub
Browse files

Update Jmespath shape traversal codegen to support multi-select lists...

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._
parent b36447e4
Loading
Loading
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment