Skip to content

feat(client): add INCREX and INCREXBYFLOAT commands#3288

Merged
nkaradzhov merged 1 commit into
redis:masterfrom
nkaradzhov:increx
May 26, 2026
Merged

feat(client): add INCREX and INCREXBYFLOAT commands#3288
nkaradzhov merged 1 commit into
redis:masterfrom
nkaradzhov:increx

Conversation

@nkaradzhov
Copy link
Copy Markdown
Collaborator

@nkaradzhov nkaradzhov commented May 22, 2026

INCREX is the integer-only path — both RESP2 and RESP3 return : integer replies in BYINT mode, so the declared return is [NumberReply, NumberReply] with no transform. Setting NUMBER:String opts the user into precision-safe string output via the decoder for values past Number.MAX_SAFE_INTEGER. by, lowerBound, and upperBound accept RedisArgument | number so callers can pass big-int strings directly.

INCREXBYFLOAT is the float-only sibling. Its wire reply differs by protocol ($ bulk string in RESP2, , double in RESP3);

Also bumps the docker test image to custom-26235535976-debian across all packages so CI picks up a server build that includes the latest INCREX API (SATURATE flag).

Integration tests cover both protocols and the precision opt-in.

Description

Describe your pull request here


Checklist

  • Does npm test pass with this change (including linting)?
  • Is the new or changed code fully tested?
  • Is a documentation update included (if this change modifies existing APIs, or introduces new ones)?

Note

Low Risk
Additive command definitions and test/CI image tag updates; no changes to auth, persistence, or existing command behavior.

Overview
Adds Redis 8.8 INCREX support to the Node client: increx for integer increments (optional BYINT, bounds, SATURATE, TTL/ENX/PERSIST) and incrExByFloat for BYFLOAT, both registered on the public command surface with broad unit and integration tests (including RESP2/3 and large-integer NUMBER:String mapping).

CI and package test defaults switch the 8.8 Redis Docker tag from 8.8-rc1 to custom-26235535976-debian so tests run against a server build that includes the current INCREX API (e.g. SATURATE).

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

@nkaradzhov nkaradzhov requested a review from PavelPashov May 22, 2026 13:06
@PavelPashov
Copy link
Copy Markdown
Contributor

INCREXBYFLOAT stringifies RESP3 doubles after they’ve already been decoded as JS numbers, so precision may already be lost.

Does it make sense to decode RESP_TYPES.DOUBLE as String for this command, or document that precision requires:

withTypeMapping({ [RESP_TYPES.DOUBLE]: String })

Copy link
Copy Markdown

@cursor cursor Bot left a comment

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 and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 596f77e. Configure here.

transformReply: {
2: undefined as unknown as () => TuplesReply<[BlobStringReply, BlobStringReply]>,
3: undefined as unknown as () => TuplesReply<[DoubleReply, DoubleReply]>
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

INCREXBYFLOAT RESP3 missing transform returns numbers not strings

High Severity

INCREXBYFLOAT declares per-protocol transformReply but both RESP2 and RESP3 entries are undefined. RESP2 happens to work because bulk strings are already JS strings, giving [string, string]. RESP3 doubles are decoded as JS number before reaching the caller, so the result is [number, number] — contradicting the PR description's promise of normalized [string, string] output and silently losing precision for values beyond Number.MAX_SAFE_INTEGER. The RESP3 slot needs an actual transform function that stringifies the decoded doubles.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 596f77e. Configure here.

INCREX is the integer-only path — both RESP2 and RESP3 return `:` integer
replies in BYINT mode, so the declared return is `[NumberReply, NumberReply]`
with no transform. Setting `NUMBER:String` opts the user into precision-safe
string output via the decoder for values past `Number.MAX_SAFE_INTEGER`.
`by`, `lowerBound`, and `upperBound` accept `RedisArgument | number` so
callers can pass big-int strings directly.

INCREXBYFLOAT is the float-only sibling. Its wire reply differs by protocol
(`$` bulk string in RESP2, `,` double in RESP3); a per-protocol transform
normalizes both elements to a plain `[string, string]` for consistent
precision-friendly output. Buffer is intentionally not exposed.

Also bumps the docker test image to custom-26235535976-debian across all
packages so CI picks up a server build that includes the latest INCREX
API (SATURATE flag).

Integration tests cover both protocols and the precision opt-in.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

fix(client): return INCREXBYFLOAT replies as native protocol types

RESP2 now returns [BlobStringReply, BlobStringReply] and RESP3 returns
[DoubleReply, DoubleReply] as pure passthroughs, matching the server's
wire behavior without lossy normalization through a stringify step.
@nkaradzhov nkaradzhov merged commit 90d5979 into redis:master May 26, 2026
14 checks passed
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.

2 participants