Skip to content

Add Support For New Bitop Operations #3001

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
fail-fast: false
matrix:
node-version: ["18", "20", "22"]
redis-version: ["rs-7.2.0-v13", "rs-7.4.0-v1", "8.0.2"]
redis-version: ["rs-7.2.0-v13", "rs-7.4.0-v1", "8.0.2", "8.2-M01-pre"]
steps:
- uses: actions/checkout@v4
with:
Expand Down
2 changes: 1 addition & 1 deletion packages/bloom/lib/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import RedisBloomModules from '.';
export default TestUtils.createFromConfig({
dockerImageName: 'redislabs/client-libs-test',
dockerImageVersionArgument: 'redis-version',
defaultDockerVersion: '8.0.2'
defaultDockerVersion: '8.2-M01-pre'
});

export const GLOBAL = {
Expand Down
70 changes: 67 additions & 3 deletions packages/client/lib/commands/BITOP.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../test-utils';
import BITOP from './BITOP';
import BITOP, { BitOperations } from './BITOP';
import { parseArgs } from './generic-transformers';

describe('BITOP', () => {
Expand All @@ -20,13 +20,77 @@ describe('BITOP', () => {
});
});

testUtils.testAll('bitOp', async client => {
for (const op of ['AND', 'OR', 'XOR'] as BitOperations[]) {
testUtils.testAll(`bitOp ${op} with non-existing keys`, async client => {
assert.equal(
await client.bitOp(op, '{tag}destKey', ['{tag}key1', '{tag}key2']),
0
);
}, {
client: GLOBAL.SERVERS.OPEN,
cluster: GLOBAL.CLUSTERS.OPEN
});

testUtils.testAll(`bitOp ${op} with existing keys`, async client => {
await client.set('{tag}key1', 'value1');
await client.set('{tag}key2', 'value2');

assert.equal(
await client.bitOp(op, '{tag}destKey', ['{tag}key1', '{tag}key2']),
6
);
}, {
client: GLOBAL.SERVERS.OPEN,
cluster: GLOBAL.CLUSTERS.OPEN
});
}

// NOT operation requires only one key
testUtils.testAll('bitOp NOT with non-existing keys', async client => {
assert.equal(
await client.bitOp('AND', '{tag}destKey', '{tag}key'),
await client.bitOp('NOT', '{tag}destKey', '{tag}key'),
0
);
}, {
client: GLOBAL.SERVERS.OPEN,
cluster: GLOBAL.CLUSTERS.OPEN
});

testUtils.testAll('bitOp NOT with existing keys', async client => {
await client.set('{tag}key', 'value');

assert.equal(
await client.bitOp('NOT', '{tag}destKey', '{tag}key'),
5
);
}, {
client: GLOBAL.SERVERS.OPEN,
cluster: GLOBAL.CLUSTERS.OPEN
});

// newer operations supported since Redis 8.2
for (const op of ['DIFF', 'DIFF1', 'ANDOR', 'ONE'] as BitOperations[]) {
testUtils.testAll(`bitOp ${op} with non-existing keys`, async client => {
assert.equal(
await client.bitOp(op, '{tag}destKey', ['{tag}key1', '{tag}key2']),
0
);
}, {
client: { ...GLOBAL.SERVERS.OPEN, minimumDockerVersion: [8, 2] },
cluster: { ...GLOBAL.CLUSTERS.OPEN, minimumDockerVersion: [8, 2] },
});

testUtils.testAll(`bitOp ${op} with existing keys`, async client => {
await client.set('{tag}key1', 'value1');
await client.set('{tag}key2', 'value2');

assert.equal(
await client.bitOp(op, '{tag}destKey', ['{tag}key1', '{tag}key2']),
6
);
}, {
client: { ...GLOBAL.SERVERS.OPEN, minimumDockerVersion: [8, 2] },
cluster: { ...GLOBAL.CLUSTERS.OPEN, minimumDockerVersion: [8, 2] },
});
}
});
4 changes: 2 additions & 2 deletions packages/client/lib/commands/BITOP.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import { CommandParser } from '../client/parser';
import { NumberReply, Command, RedisArgument } from '../RESP/types';
import { RedisVariadicArgument } from './generic-transformers';

export type BitOperations = 'AND' | 'OR' | 'XOR' | 'NOT';
export type BitOperations = 'AND' | 'OR' | 'XOR' | 'NOT' | 'DIFF' | 'DIFF1' | 'ANDOR' | 'ONE';

export default {
IS_READ_ONLY: false,
/**
* Performs bitwise operations between strings
* @param parser - The Redis command parser
* @param operation - Bitwise operation to perform: AND, OR, XOR, NOT
* @param operation - Bitwise operation to perform: AND, OR, XOR, NOT, DIFF, DIFF1, ANDOR, ONE
* @param destKey - Destination key to store the result
* @param key - Source key(s) to perform operation on
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/client/lib/sentinel/test-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ export class SentinelFramework extends DockerBase {
this.#testUtils = TestUtils.createFromConfig({
dockerImageName: 'redislabs/client-libs-test',
dockerImageVersionArgument: 'redis-version',
defaultDockerVersion: '8.0.2'
defaultDockerVersion: '8.2-M01-pre'
});
this.#nodeMap = new Map<string, ArrayElement<Awaited<ReturnType<SentinelFramework['spawnRedisSentinelNodes']>>>>();
this.#sentinelMap = new Map<string, ArrayElement<Awaited<ReturnType<SentinelFramework['spawnRedisSentinelSentinels']>>>>();
Expand Down
2 changes: 1 addition & 1 deletion packages/client/lib/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import RedisBloomModules from '@redis/bloom';
const utils = TestUtils.createFromConfig({
dockerImageName: 'redislabs/client-libs-test',
dockerImageVersionArgument: 'redis-version',
defaultDockerVersion: '8.0.2'
defaultDockerVersion: '8.2-M01-pre'
});

export default utils;
Expand Down
2 changes: 1 addition & 1 deletion packages/entraid/lib/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { EntraidCredentialsProvider } from './entraid-credentials-provider';
export const testUtils = TestUtils.createFromConfig({
dockerImageName: 'redislabs/client-libs-test',
dockerImageVersionArgument: 'redis-version',
defaultDockerVersion: '8.0.2'
defaultDockerVersion: '8.2-M01-pre'
});

const DEBUG_MODE_ARGS = testUtils.isVersionGreaterThan([7]) ?
Expand Down
2 changes: 1 addition & 1 deletion packages/json/lib/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import RedisJSON from '.';
export default TestUtils.createFromConfig({
dockerImageName: 'redislabs/client-libs-test',
dockerImageVersionArgument: 'redis-version',
defaultDockerVersion: '8.0.2'
defaultDockerVersion: '8.2-M01-pre'
});

export const GLOBAL = {
Expand Down
2 changes: 1 addition & 1 deletion packages/search/lib/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { RespVersions } from '@redis/client';
export default TestUtils.createFromConfig({
dockerImageName: 'redislabs/client-libs-test',
dockerImageVersionArgument: 'redis-version',
defaultDockerVersion: '8.0.2'
defaultDockerVersion: '8.2-M01-pre'
});

export const GLOBAL = {
Expand Down
2 changes: 1 addition & 1 deletion packages/time-series/lib/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import TimeSeries from '.';
export default TestUtils.createFromConfig({
dockerImageName: 'redislabs/client-libs-test',
dockerImageVersionArgument: 'redis-version',
defaultDockerVersion: '8.0.2'
defaultDockerVersion: '8.2-M01-pre'
});

export const GLOBAL = {
Expand Down
Loading