palashc opened a new pull request, #2468:
URL: https://github.com/apache/phoenix/pull/2468
### What changes were proposed in this pull request?
Adds the `$LIST_APPEND` operator to the BSON SET update-expression layer in
`UpdateExpressionUtils`. Inside a `$SET` block the new operator accepts:
```
{ "$SET": { "<path>": { "$LIST_APPEND": [<op1>, <op2>] } } }
```
Each operand resolves to a `BsonArray` via one of:
- a literal `BsonArray`
- a `BsonString` naming a top-level or nested document path (existing value
must be an array)
- a `{ "$IF_NOT_EXISTS": { "<path>": <fallback> } }` document whose resolved
value must be an array
The result is `op1 ⧺ op2` with order and duplicates preserved. The operator
slots in alongside the existing `$ADD` / `$SUBTRACT` / `$IF_NOT_EXISTS` cases
in `getNewFieldValue`; the resolved `BsonArray` is then written back via the
existing nested-path SET machinery, so no changes are required to
`updateNestedField`, `updateArrayAtLeafNode`, or `updateDocumentAtLeafNode`.
Nested `$LIST_APPEND` operands and arity ≠ 2 are explicitly rejected.
### Why are the changes needed?
The BSON update-expression engine today supports `$SET` / `$UNSET` / `$ADD`
/ `$DELETE_FROM_SET` / `$IF_NOT_EXISTS` / arithmetic `$ADD` / `$SUBTRACT`, but
has no primitive for appending to an existing list. Downstream services that
maintain append-only queues or event lists in a BSON column have to perform a
read-modify-write cycle today, which doesn't compose with the atomic
single-statement semantics the other operators already provide. This change
rounds out the list-valued update surface so an append (or create-or-append)
composes naturally with sibling `$ADD` / `$IF_NOT_EXISTS` clauses inside the
same `$SET` block.
### Does this PR introduce _any_ user-facing change?
Yes — a new optional operator `$LIST_APPEND` is accepted inside `$SET`. No
existing behavior changes: update expressions that did not use `$LIST_APPEND`
previously continue to be evaluated identically.
### How was this patch tested?
- 15 new unit tests in `UpdateExpressionUtilsTest` covering:
- all three accepted operand shapes (literal array, path string,
`$IF_NOT_EXISTS`),
- the canonical "create-or-append on a missing field" pattern via
`$IF_NOT_EXISTS` with an empty-array fallback,
- all rejection cases (missing path with no `$IF_NOT_EXISTS`, path to a
non-array, non-array `:placeholder`, `$IF_NOT_EXISTS` fallback that resolves to
a non-array, nested `$LIST_APPEND`, arity ≠ 2),
- result semantics (duplicates and order preserved, heterogeneous element
types, empty operands),
- nested document-path target (`nested.queue`),
- array-index target (`matrix[0]`),
- composition with a sibling `$ADD` in the same `$SET` block.
Runs in ~0.7s. `UpdateExpressionUtilsTest`: 23/23 pass (8 pre-existing +
15 new).
- 1 new end-to-end IT in `Bson2IT.testListAppendUpdateExpression` exercising
the full SQL → BSON wire pipeline via `BSON_UPDATE_EXPRESSION(...)` in `ON
DUPLICATE KEY UPDATE`. Two write-then-read phases on one row: a basic append to
an existing list, and a create-or-append using `$IF_NOT_EXISTS` composed with a
sibling `$ADD` on a numeric counter in the same `$SET`. 1/1 pass in ~57s on the
standard mini-cluster.
### Was this patch authored or co-authored using generative AI tooling?
Generated-by: Cursor (Claude Opus 4.7)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]