Skip to content

feat(client): add LMOVEM and BLMOVEM commands#3340

Open
nkaradzhov wants to merge 4 commits into
redis:masterfrom
nkaradzhov:move-between-lists
Open

feat(client): add LMOVEM and BLMOVEM commands#3340
nkaradzhov wants to merge 4 commits into
redis:masterfrom
nkaradzhov:move-between-lists

Conversation

@nkaradzhov

@nkaradzhov nkaradzhov commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

This pull request adds the LMOVEM and BLMOVEM commands to @redis/client, closing the gap where only a single element could be moved between lists (LMOVE/BLMOVE) while the pop family already moved many.

  • LMOVEM source destination <LEFT|RIGHT> <LEFT|RIGHT> [<COUNT|EXACTLY> count <OBO|BULK>] — moves up to (COUNT) or exactly (EXACTLY) N elements from one end of the source list to one end of the destination; reply is always an array of moved elements (destination order), or null when nothing moved.
  • BLMOVEM — blocking variant, same options plus a timeout (seconds, 0 = forever).

API

Options are modeled as a discriminated union — { COUNT: number, ORDER?: 'OBO' | 'BULK' } XOR { EXACTLY: number, ORDER?: 'OBO' | 'BULK' } — so COUNT/EXACTLY are mutually exclusive at the type level, and ORDER (OBO = stack/reversed, BULK = queue/preserved) only applies when a count is given. Omitting options moves a single element, still as an array reply. Both raw and camelCase aliases are exposed (LMOVEM/lMoveM, BLMOVEM/blMoveM).

Considerations

  • New commands (not options on LMOVE/BLMOVE) so the reply type never changes with arguments.
  • Single-slot multi-key: source and destination must be hash-tag collocated in cluster mode; specs use {tag} prefixes.
  • Commands are unreleased upstream, so behavior tests were authored but not executed locally (no server build exposing LMOVEM); argument serialization is type-checked and asserted via parseArgs.

🤖 Generated with Claude Code


Note

Low Risk
Additive client command definitions and tests only; no changes to existing LMOVE/BLMOVE behavior or core connection logic.

Overview
Adds Redis 8.10 list commands LMOVEM and BLMOVEM to @redis/client, exposing bulk move between two lists (alongside existing single-element LMOVE / BLMOVE).

lMoveM / LMOVEM moves one or more elements between source and destination list ends; replies are always a string array (or null when nothing moves), including the default single-element case. Optional LMoveMOptions are a typed union: COUNT (up to N, clamped) or EXACTLY (all-or-nothing), plus optional ORDER OBO vs BULK. Shared parseLMoveMOptions serializes the trailing Redis args for both commands.

blMoveM / BLMOVEM mirrors that API with a blocking timeout before the options tail and reuses LMOVEM’s reply typing. Both are registered in the command index with raw and camelCase aliases.

Specs gate on version ≥ 8.10, assert parseArgs wire format, and include integration tests (cluster-safe {tag} keys) for ordering, empty source, timeout, and EXACTLY failure when the source is too short.

Reviewed by Cursor Bugbot for commit ef8c325. Bugbot is set up for automated code reviews on this repo. Configure here.

nkaradzhov and others added 4 commits July 14, 2026 15:17
Add LMOVEM and its blocking variant BLMOVEM to move multiple elements
between two lists in a single command, closing the gap where only one
element could be moved (LMOVE/BLMOVE) while the pop family already
supported many.

Options are modeled as a discriminated union so COUNT and EXACTLY are
mutually exclusive at the type level, each with an optional OBO|BULK
ordering. Reply is always an array of moved elements (destination
order) or null when nothing moved. Single-slot multi-key: specs use
hash-tag collocated keys for cluster.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add isVersionGreaterThanHook([8, 10]) so behavior tests run only on
Redis 8.10+, and add @SInCE 8.10 to the LMOVEM/BLMOVEM registry JSDoc.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the single-caller parseLMoveMArguments helper; BLMOVEM cannot
reuse it (timeout sits mid-args), so it was dead abstraction.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Extract parseLMoveMOptions helper shared by LMOVEM and BLMOVEM
- Correct BLMOVEM JSDoc blocking-semantics wording (COUNT unblocks at 1)
- Add @see redis.io links to LMOVEM/BLMOVEM entries
- Cover no-options single-element reply, COUNT clamping, EXACTLY-too-few

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@nkaradzhov
nkaradzhov marked this pull request as ready for review July 14, 2026 13:27
@nkaradzhov
nkaradzhov requested a review from PavelPashov July 14, 2026 13:28

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit ef8c325. Configure here.

EXACTLY: 3,
ORDER: 'BULK'
})
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

EXACTLY test expects rejection

Medium Severity

The integration test for EXACTLY with too few source elements uses assert.rejects, but the PR and LMoveMOptions JSDoc describe moving nothing as a successful no-op with a null reply, not a command error.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ef8c325. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant