Skip to content

fix: DynamoDB expression evaluation, UpdateExpression paths, and ConsumedCapacity#197

Open
diopolgg wants to merge 6 commits intofloci-io:mainfrom
flipadmin:diopol/dynamodb-expression-fixes
Open

fix: DynamoDB expression evaluation, UpdateExpression paths, and ConsumedCapacity#197
diopolgg wants to merge 6 commits intofloci-io:mainfrom
flipadmin:diopol/dynamodb-expression-fixes

Conversation

@diopolgg
Copy link
Copy Markdown

@diopolgg diopolgg commented Apr 3, 2026

Summary

This PR fixes several DynamoDB compatibility issues and adds ConsumedCapacity support:

1. Replace regex-based expression evaluation with AST parser (fix)

The old regex/string-splitting approach for filter, condition, and key condition expressions broke on several valid DynamoDB patterns:

Adds ExpressionEvaluator with a proper tokenizer → recursive-descent parser → AST evaluator. Also fixes GSI sparse-index semantics: items where any GSI key attribute is null/missing are now excluded from GSI query results, matching real DynamoDB behavior.

2. Support dotted paths in UpdateExpression and fix clause boundary parsing (fix)

Two bugs in applyUpdateExpression:

  • Dotted paths (e.g. #details.subkey = :val) were not resolved segment-by-segment — the entire string was looked up as a single ExpressionAttributeName, failing silently. Now each segment is resolved independently and nested Map nodes are navigated/created as needed.

  • SET/REMOVE clause boundaryfindNextComma was checked before findNextClauseKeyword, so SET #a = :v1 REMOVE #b,#c would treat the comma in the REMOVE list as a SET separator, corrupting both clauses.

3. Add ConsumedCapacity in DynamoDB responses (feat)

  • Returns ConsumedCapacity in GetItem, PutItem, DeleteItem, UpdateItem, Query, Scan, BatchGetItem, BatchWriteItem when ReturnConsumedCapacity is TOTAL or INDEXES.
  • For INDEXES level, includes per-table and per-GSI capacity breakdown.
  • Adds ProvisionedThroughput to GSI descriptions in DescribeTable (was missing, causing clients that read GSI throughput to fail).
  • Simple capacity estimates: 0.5 RCU per item read, 1.0 WCU per write.

Tests

Unit & integration tests (main project)

  • ExpressionEvaluatorTest: 64 tests covering tokenizer, parser, key-condition splitting, and evaluator (logic, comparisons, functions, nested parens, compact format, expression attribute names)
  • DynamoDbServiceTest: new tests for dotted path SET/REMOVE, SET+REMOVE clause boundary, compact BETWEEN queries
  • DynamoDbIntegrationTest: 4 new integration tests for ConsumedCapacity (TOTAL, INDEXES, omission when not requested)
  • DynamoDbFilterExpressionIntegrationTest: 14 new HTTP-level integration tests for BOOL <>/=, IN operator, OR/NOT operators, nested parentheses, parenthesized BETWEEN, and compact-format key conditions

All 1468 tests pass.

Compatibility tests (SDK against live Floci)

  • DynamoDbExpressionTests (new, 14 tests): end-to-end AWS SDK v2 tests covering filter expressions (BOOL, IN, OR, NOT, nested parens), dotted UpdateExpression paths, ConsumedCapacity (TOTAL/NONE for Scan/GetItem/PutItem), and parenthesized BETWEEN in KeyConditionExpression (standard and compact format)
  • Surefire include fix: added **/*Tests.java pattern to compatibility-tests/sdk-test-java/pom.xml — several existing test classes (DynamoDbScanConditionTests, EcsTests, Ec2Tests, etc.) were silently skipped because surefire only matched **/*Test.java

All 38 DynamoDB compatibility tests pass (18 existing + 6 previously skipped + 14 new).

@hectorvent
Copy link
Copy Markdown
Collaborator

Hi @diopolgg,

Thanks for taking the time to contribute! We've seen your PR and will take a look soon.

To ensure this implementation stays robust, could you also open a PR in our compatibility suite at https://github.com/hectorvent/floci-compatibility-tests? This helps us validate that your changes keep working perfectly as the project evolves.

Also check conflicts with main branch,

The Floci team

@hectorvent
Copy link
Copy Markdown
Collaborator

Hi @diopolgg, tests project embedded directly in this project please sync with main, solve conflicts and get the test implemented. Test directory is compatibility-tests.

Thanks

Copy link
Copy Markdown
Collaborator

@hectorvent hectorvent left a comment

Choose a reason for hiding this comment

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

Conflicts changes required

diopolgg and others added 4 commits April 7, 2026 11:48
The old regex/string-splitting approach for filter, condition, and key
condition expressions broke on several valid DynamoDB patterns:
- <> comparisons on BOOL attributes (missing attribute handling)
- IN operator (fell through to pass-all)
- OR / NOT logical operators (only AND was implemented)
- Parenthesized BETWEEN: pk = :pk AND (sk BETWEEN :start AND :end)
- Compact format: (#f0 = :v0)AND(#f1 BETWEEN :v1 AND :v2)

Adds ExpressionEvaluator with a proper tokenizer → recursive-descent
parser → AST evaluator, and integrates it into DynamoDbService replacing
matchesFilterExpression, evaluateCondition, and queryWithExpression's
key-condition splitting and SK evaluation.

Also fixes GSI sparse-index semantics: items where any GSI key attribute
is null/missing are now excluded from GSI query results, matching real
DynamoDB behavior.

Bonus: correctly handles numeric ExpressionAttributeNames (#0, floci-io#1) that
the old tokenizer missed (relates to floci-io#127).
…se boundary parsing

Two bugs in applyUpdateExpression:

1. Dotted paths (e.g. `#details.subkey = :val`) were not resolved
   segment-by-segment — the entire `#details.subkey` was looked up as
   a single ExpressionAttributeName, failing silently. Now each segment
   is resolved independently and nested DynamoDB Map nodes are
   navigated/created as needed.

2. SET clause parsing used findNextComma before findNextClauseKeyword,
   so when the last SET value was followed by `REMOVE a,b,c`, the comma
   in the REMOVE list was treated as a SET assignment separator. This
   caused the last SET assignment to absorb part of the REMOVE list and
   silently fail. Now clause keywords are checked before commas.
…n DescribeTable

- Return ConsumedCapacity in GetItem, PutItem, DeleteItem, UpdateItem,
  Query, Scan, BatchGetItem, BatchWriteItem responses when
  ReturnConsumedCapacity is TOTAL or INDEXES.
- For INDEXES level, include per-table and per-GSI capacity breakdown.
- Add ProvisionedThroughput to GSI descriptions in DescribeTable
  responses (was missing, causing clients that read GSI throughput to
  fail).
- Simple capacity estimates: 0.5 RCU per item read, 1.0 WCU per write.
…licts

- Add DynamoDbExpressionTests covering filter expressions (BOOL, IN, OR,
  NOT, nested parens), dotted UpdateExpression paths, ConsumedCapacity,
  and parenthesized BETWEEN in KeyConditionExpression
- Add DynamoDbFilterExpressionIntegrationTest for HTTP-level validation
- Fix stale trimBalancedOuterParens references left after rebase conflict
  resolution (method was replaced by ExpressionEvaluator AST parser)
- Fix surefire include pattern to also run *Tests.java files that were
  silently skipped (DynamoDbScanConditionTests, EcsTests, Ec2Tests, etc.)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@diopolgg diopolgg force-pushed the diopol/dynamodb-expression-fixes branch from 6b615d5 to d019253 Compare April 7, 2026 11:08
@diopolgg diopolgg requested a review from hectorvent April 7, 2026 11:10
…ssion-fixes

# Conflicts:
#	src/main/java/io/github/hectorvent/floci/services/dynamodb/DynamoDbJsonHandler.java
#	src/test/java/io/github/hectorvent/floci/services/dynamodb/DynamoDbServiceTest.java
@diopolgg
Copy link
Copy Markdown
Author

diopolgg commented Apr 9, 2026

Resolved merge conflicts with latest main. All unit tests (1725) pass, and Java compatibility tests (DynamoDB expression, scan condition, and all other services) pass against a live Floci instance. Ready for re-review.

…ssion-fixes

# Conflicts:
#	src/main/java/io/github/hectorvent/floci/services/dynamodb/DynamoDbService.java
#	src/test/java/io/github/hectorvent/floci/services/dynamodb/DynamoDbServiceTest.java
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants