fix(dynamodb): paren-wrapped KeyCondition clauses and nested-path SET targets#660
Merged
vieiralucas merged 6 commits intofaiscadev:mainfrom Apr 22, 2026
Merged
Conversation
… targets
Two silent-failure bugs in the expression evaluator, both triggered by the
shape aws-sdk-go-v2's builders emit:
1. `(store_id = :s) AND (order_id > :a)` returned 0 rows.
`evaluate_single_key_condition` never called `strip_outer_parens`, so each
split clause reached the leaf evaluator with outer parens intact.
`part.find('=')` then sliced `left = "(store_id"`, which as an attribute
name is absent — silent false. Restructured `evaluate_key_condition` to
mirror `evaluate_filter_expression`: recursive, with paren-strip +
top-level AND split.
2. `SET #web.#tab_id = :tab` silently created a literal top-level attribute
named `"#web.#tab_id"` instead of updating the nested map. `resolve_attr_name`
only matches single `#`-prefixed tokens. Dotted paths now route through a
new `assign_nested_path` helper that resolves each segment via
`expr_attr_names` and walks the M structure. Writing through a missing
parent returns ValidationException, matching real DynamoDB.
Also adds `service/expression_corpus_tests.rs`: 33 table-driven tests seeded
from aws-sdk-go-v2's builder output shapes and moto's parsing tests.
5 known gaps discovered during corpus construction are marked `#[ignore]`
with descriptive reasons for follow-up (BETWEEN-in-compound, size-no-space,
tab whitespace, filter-LHS dot paths).
Test plan:
- `cargo test -p fakecloud-dynamodb` — 209 pass, 5 known-gap ignores
- `cargo clippy -p fakecloud-dynamodb --all-targets -- -D warnings` — clean
- `cargo fmt` — clean
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Hoist invalid_document_path() helper; replaces 5 inline constructions in assign_list_index and assign_nested_path. - Drop redundant leaf.clone() in assign_nested_path by consuming the segments Vec via pop + remove. - Flip is_dotted_path short-circuit: the `.` check comes first since most SET targets have neither dot nor bracket. - Remove 5 test_evaluate_key_condition_* unit tests — fully covered by the corpus file. - Drop redundant `type AttributeValue = Value` alias in the corpus; import from super:: instead. - Strip narrating comments (PR refs, "Before fix:", seeded-date) from the corpus and keep only grammar-shape explanations. No behavior change. cargo test / clippy / fmt clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
1 issue found across 2 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="crates/fakecloud-dynamodb/src/service/mod.rs">
<violation number="1" location="crates/fakecloud-dynamodb/src/service/mod.rs:1732">
P2: Dotted-path SET handling can return success without applying any update when RHS is not directly resolvable, silently dropping assignments.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
… args apply_set_assignment previously returned Ok(()) when a dotted-path SET target (SET #a.#b = <rhs>) received an RHS that resolve_value couldn't handle (if_not_exists, list_append, arithmetic). That is the exact silent-failure class this file already fights elsewhere — return ValidationException instead. While in here, drop the hash_key_name / range_key_name parameters from evaluate_key_condition and the _hash_key_name placeholder from evaluate_single_key_condition. Both were threaded through the recursion but never read at the leaf, guarded only by a clippy allow. Corpus guards: - update_set_nested_path_complex_rhs_errors_cleanly locks in the ValidationException behavior and asserts the parent map is untouched. - update_set_nested_path_complex_rhs is ignored and documents the underlying gap (complex RHS into a nested path).
Two regressions fixed by this branch were reproducible end-to-end via the SDK. Lock them in at the HTTP boundary in both test suites: crates/fakecloud-e2e (Rust aws_sdk_dynamodb): - dynamodb_query_paren_wrapped_key_condition — Query with bare, paren- wrapped, and SDK-placeholder KeyConditionExpression shapes must all return the same rows. - dynamodb_update_nested_set_path — SET #web.#tab_id = :tab must update the nested map in place, preserve sibling keys, and not leak a literal "#web.#tab_id" top-level attribute. sdks/go/e2e (Go aws-sdk-go-v2): - TestE2EDynamoDBParenKeyCondition — same three shapes as the Rust test, using the exact grammar the Go KeyConditionBuilder emits. - TestE2EDynamoDBNestedSetPath — same nested-SET guard for the Go UpdateItem path.
Member
|
Pushed two follow-up commits directly (
Tests green locally: |
…ted-set-review # Conflicts: # sdks/go/e2e/e2e_test.go
The sdks/go/e2e/e2e_test.go merge conflict was resolved against the pre-main import block, which dropped the scheduler/schedtypes/sqstypes imports main added alongside TestSchedulerGetSchedules and TestSchedulerFireSchedule. Restore them so the merged file builds.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two silent-failure bugs in the DynamoDB expression evaluator, both triggered by output shapes the
aws-sdk-go-v2expression builder emits. Same class as #257, #261, #368 — hand-rolled string scanning that misses a grammar context.1. Parenthesised clauses in
KeyConditionExpressionsilently return zero rowsRepro against 0.9.2:
The shape that reliably hits this is what the
aws-sdk-go-v2key-condition builder emits for a compound:(#0 = :0) AND (#1 > :1). So every caller composing KeyConditions through the official SDK saw silent empty results.Root cause:
split_on_andis paren-aware and correctly leaves each clause's outer parens intact, butevaluate_single_key_condition(the leaf evaluator) never calledstrip_outer_parensbefore searching for a comparison operator.part.find('=')on"(store_id = :s)"returns position 11, slicingleft = "(store_id", which as an attribute name is absent from the item — the comparison silently evaluates to false.Fix: restructure
evaluate_key_conditionto mirrorevaluate_filter_expression(already correctly paren-handling): recursive, with top-level AND split and outer-paren stripping at each frame.2.
SET #a.#b = :vsilently creates a top-level attribute named"#a.#b"Repro against 0.9.2:
Root cause:
apply_set_assignmentcalledresolve_attr_name("#web.#tab_id", ...)on the whole LHS.resolve_attr_nameonly handles a single#namelookup — it saw the dotted path as one token, missed the match, and returned the literal string.item.insert("#web.#tab_id", value)then created a top-level attribute with that name instead of updating the nested map. No error, no side-effect visible to the caller.Fix: detect dotted LHS paths in
apply_set_assignment(is_dotted_pathhelper) and route them through a newassign_nested_pathhelper that resolves each#-prefixed segment and walks theMstructure. Only plain-value RHS is supported in this first pass (noif_not_exists/list_append/ arithmetic into a nested path — those shapes aren't common and can be added when needed). Writing through a missing parent returnsValidationException, matching real DynamoDB.3. Corpus-driven test file (new)
Added
crates/fakecloud-dynamodb/src/service/expression_corpus_tests.rs— 28 table-driven tests, one per dimension of the grammar (operators, paren shapes, SDK-builder output, functions with/without space before paren,IN,BETWEEN, nested paths, compound updates, etc.). Cases are seeded fromaws-sdk-go-v2/feature/dynamodb/expressionandmoto/dynamodb/parsing/.While building the corpus I also surfaced 5 pre-existing grammar gaps that aren't fixed in this PR — they're marked
#[ignore = "known gap: ..."]with a description of the root cause. CI stays green; each ignored test is a work item:BETWEENinside a compound expression (split_on_andgrabs BETWEEN's inner AND) — affects both KeyCondition and Filter.size(X)without a space before the paren.These can be tackled incrementally without blocking this fix.
Test plan
expression_corpus_tests.rs— 28 tests.cargo test -p fakecloud-dynamodb— 204 pass, 5 known-gap ignored.cargo clippy -p fakecloud-dynamodb --all-targets -- -D warnings— clean.cargo fmt --check— clean.WSConnectionsService.SetTabContextflow (which hits both bugs in sequence) now works; previously it was writing"#web.#tab_id"as a top-level attribute and then failing to read it back.SET a.b = :vwrites intoa's map per the UpdateExpression SET docs.Summary by cubic
Fixes two DynamoDB expression bugs that could return empty Query results and write wrong updates when using
aws-sdk-go-v2-generated expressions. Adds a corpus and end-to-end tests, and now rejects unsupported nested-path RHS instead of silently succeeding.Bug Fixes
(#0 = :0) AND (#1 > :1)and returns correct rows.SET #web.#tab_id = :tab) resolve each#segment and update the nested map. Missing parents raise ValidationException. Unresolvable/complex RHS into nested paths now raise ValidationException instead of silently doing nothing.sdks/go/e2eafter merge to keep tests green.New Features
fakecloud-dynamodb(33 tests) covering operators, paren shapes, SDK output, IN/BETWEEN, functions, and nested paths (5 known gaps are ignored).fakecloud-e2eandsdks/go/e2efor paren-wrapped KeyCondition and nested-path SET to ensure SDK-shaped requests behave correctly.Written for commit d9b6cac. Summary will update on new commits.