fix(dynamodb): handle AND/OR/parens in ConditionExpression#257
Merged
vieiralucas merged 1 commit intofaiscadev:mainfrom Apr 11, 2026
Merged
Conversation
evaluate_condition passed the whole ConditionExpression string to parse_simple_comparison, which splits on the first `<>`/`=` it finds. For any expression composed through the AWS SDK's expression builder — which wraps clauses in parentheses by default — this produced garbage attribute and value references and returned the wrong result: (#s <> :c) AND (#s <> :f) → silently fails (#s = :c) → silently succeeds on mismatch Any consumer using `NotEqual().And(...)` or similar compound shapes through aws-sdk-go / aws-sdk-rust was affected. Rewrite evaluate_condition to delegate to a recursive helper that mirrors evaluate_filter_expression: split on OR (lowest precedence), split on AND, strip outer parentheses, recurse, and evaluate a single leaf comparison at the bottom. Leaf semantics are unchanged — the existing attribute_exists / attribute_not_exists / = / <> logic is extracted into evaluate_single_condition with no behavioral difference. Six new unit tests cover the condition shapes that were broken: parenthesised <>, parenthesised = mismatch, compound (<>) AND (<>), compound (=) AND (=) mismatch, compound (=) OR (=), plus a baseline bare <> test as a regression guard.
There was a problem hiding this comment.
2 issues found across 1 file
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.rs">
<violation number="1" location="crates/fakecloud-dynamodb/src/service.rs:3922">
P2: ConditionExpression parsing can panic on non‑ASCII input because split_on_or/and slice the UTF‑8 string at byte indices; the new call introduces this risk into ConditionExpression handling.</violation>
<violation number="2" location="crates/fakecloud-dynamodb/src/service.rs:3930">
P2: ConditionExpression logical parsing is whitespace-fragile: AND/OR are only recognized as literal " AND "/" OR ", causing compound expressions without that exact spacing to be mis-evaluated.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| let trimmed = expr.trim(); | ||
|
|
||
| // Split on OR first (lower precedence), respecting parentheses. | ||
| let or_parts = split_on_or(trimmed); |
There was a problem hiding this comment.
P2: ConditionExpression parsing can panic on non‑ASCII input because split_on_or/and slice the UTF‑8 string at byte indices; the new call introduces this risk into ConditionExpression handling.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/fakecloud-dynamodb/src/service.rs, line 3922:
<comment>ConditionExpression parsing can panic on non‑ASCII input because split_on_or/and slice the UTF‑8 string at byte indices; the new call introduces this risk into ConditionExpression handling.</comment>
<file context>
@@ -3895,57 +3895,88 @@ fn evaluate_condition(
+ let trimmed = expr.trim();
+
+ // Split on OR first (lower precedence), respecting parentheses.
+ let or_parts = split_on_or(trimmed);
+ if or_parts.len() > 1 {
+ return or_parts.iter().any(|part| {
</file context>
|
|
||
| if let Some(inner) = extract_function_arg(cond, "attribute_not_exists") { | ||
| // Then split on AND (higher precedence), respecting parentheses. | ||
| let and_parts = split_on_and(trimmed); |
There was a problem hiding this comment.
P2: ConditionExpression logical parsing is whitespace-fragile: AND/OR are only recognized as literal " AND "/" OR ", causing compound expressions without that exact spacing to be mis-evaluated.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/fakecloud-dynamodb/src/service.rs, line 3930:
<comment>ConditionExpression logical parsing is whitespace-fragile: AND/OR are only recognized as literal " AND "/" OR ", causing compound expressions without that exact spacing to be mis-evaluated.</comment>
<file context>
@@ -3895,57 +3895,88 @@ fn evaluate_condition(
- if let Some(inner) = extract_function_arg(cond, "attribute_not_exists") {
+ // Then split on AND (higher precedence), respecting parentheses.
+ let and_parts = split_on_and(trimmed);
+ if and_parts.len() > 1 {
+ return and_parts.iter().all(|part| {
</file context>
Member
|
Thank you @Bowbaq |
vieiralucas
added a commit
that referenced
this pull request
Apr 11, 2026
…aluation - Delete evaluate_condition_expression and evaluate_single_condition, which duplicated evaluate_filter_expression and evaluate_single_filter_condition with divergent feature sets (the root cause of the bug PR #257 fixed) - evaluate_condition now delegates to evaluate_filter_expression with an empty HashMap for missing items, which correctly models "item doesn't exist" - Conditions automatically gain begins_with, contains, BETWEEN, and all comparison operators that were previously only available in FilterExpression - Add NOT operator support to evaluate_filter_expression (DynamoDB grammar) - Remove dead parse_simple_comparison function (subsumed by evaluate_single_key_condition) - Add test helpers (cond_item, cond_names, cond_values) to reduce boilerplate - Add tests for NOT, begins_with, contains in conditions, and missing-item edge cases
5 tasks
vieiralucas
added a commit
that referenced
this pull request
Apr 11, 2026
…aluation - Delete evaluate_condition_expression and evaluate_single_condition, which duplicated evaluate_filter_expression and evaluate_single_filter_condition with divergent feature sets (the root cause of the bug PR #257 fixed) - evaluate_condition now delegates to evaluate_filter_expression with an empty HashMap for missing items, which correctly models "item doesn't exist" - Conditions automatically gain begins_with, contains, BETWEEN, and all comparison operators that were previously only available in FilterExpression - Add NOT operator support to evaluate_filter_expression (DynamoDB grammar) - Remove dead parse_simple_comparison function (subsumed by evaluate_single_key_condition) - Add test helpers (cond_item, cond_names, cond_values) to reduce boilerplate - Add tests for NOT, begins_with, contains in conditions, and missing-item edge cases
3 tasks
7 tasks
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
evaluate_conditionhad no handling forAND,OR, or parentheses — it passed the fullConditionExpressiontoparse_simple_comparison, which splits on the first<>/=it finds. Any consumer composing conditions through aws-sdk's expression builder hit this: the builder wraps clauses in parens by default, so(#0 <> :0) AND (#0 <> :1)split intoleft="(#0 "and a garbage right-hand side, and the result was accidental — silent failure for<>, silent success for=.Repro against 0.7.0:
Fix:
evaluate_conditionnow delegates to a recursive helper that mirrorsevaluate_filter_expression— split on OR, split on AND, strip outer parens, recurse, evaluate a single leaf at the bottom. The leaf (attribute_exists/attribute_not_exists/=/<>) is extracted intoevaluate_single_conditionwith no behavioral change, reusing existing helpers.Test plan
service.rscovering bare<>, parenthesised<>/=, compound(<>) AND (<>), compound(=) AND (=)mismatch, and compound(=) OR (=). Each was verified to fail againstmainbefore the fix and pass after.cargo test -p fakecloud-dynamodb— 52 passcargo test --workspace --exclude fakecloud-e2e— all passcargo test -p fakecloud-e2e --test dynamodb— 36 passcargo clippy --workspace -- -D warnings— cleancargo fmt --check— cleanConditionExpressiongrammar (AND,OR,NOT, parentheses), and the bug was specifically that fakecloud didn't.Summary by cubic
Fix ConditionExpression evaluation in
fakecloud-dynamodbto correctly support AND, OR, and parentheses. This aligns behavior with DynamoDB and fixes wrong results from SDK-built expressions.attribute_exists,attribute_not_exists,=, and<>are unchanged.Written for commit 867427f. Summary will update on new commits.