# Redis Commands

ioredis provides complete Redis command support through the RedisCommander interface. All Redis commands are available as methods with proper TypeScript typing, promise-based returns, and optional callback support.

## Capabilities

### Command Execution

All Redis commands are available as methods on Redis and Cluster instances with consistent patterns.

```typescript { .api }
// Generic command execution
call(command: string, ...args: any[]): Promise<unknown>;

// Example command signatures
get(key: RedisKey): Promise<string | null>;
set(key: RedisKey, value: RedisValue): Promise<"OK">;
set(key: RedisKey, value: RedisValue, expiryMode: "EX", time: number): Promise<"OK">;
set(key: RedisKey, value: RedisValue, expiryMode: "PX", time: number): Promise<"OK">;
set(key: RedisKey, value: RedisValue, mode: "NX"): Promise<"OK" | null>;
set(key: RedisKey, value: RedisValue, mode: "XX"): Promise<"OK" | null>;

// All commands also support callback pattern
get(key: RedisKey, callback: Callback<string | null>): void;
set(key: RedisKey, value: RedisValue, callback: Callback<"OK">): void;
```

**Usage Examples:**

```typescript
import Redis from "ioredis";

const redis = new Redis();

// Promise-based usage
const value = await redis.get("key");
await redis.set("key", "value");

// Callback usage
redis.get("key", (err, result) => {
  if (err) console.error(err);
  else console.log(result);
});

// Complex command with options
await redis.set("session:123", "data", "EX", 3600, "NX");

// Generic command execution
const result = await redis.call("CUSTOM_COMMAND", "arg1", "arg2");
```

### Buffer Command Variants

All Redis commands have corresponding buffer variants that work with binary data and return Buffer objects instead of strings.

```typescript { .api }
// Every command has a Buffer variant
getBuffer(key: RedisKey): Promise<Buffer | null>;
setBuffer(key: RedisKey, value: RedisValue): Promise<Buffer>;
hgetBuffer(key: RedisKey, field: string): Promise<Buffer | null>;
lrangeBuffer(key: RedisKey, start: number, stop: number): Promise<Buffer[]>;

// Generic buffer command execution
callBuffer(command: string, ...args: any[]): Promise<Buffer>;
```

**Usage Examples:**

```typescript
// Working with binary data
const binaryData = Buffer.from("hello world", "utf8");
await redis.setBuffer("binary:key", binaryData);

const result = await redis.getBuffer("binary:key"); // Returns Buffer
console.log(result.toString()); // "hello world"

// Hash operations with buffers
await redis.hsetBuffer("hash:key", "field", Buffer.from("value"));
const hashValue = await redis.hgetBuffer("hash:key", "field"); // Returns Buffer

// List operations with buffers
await redis.lpushBuffer("list:key", Buffer.from("item1"), Buffer.from("item2"));
const items = await redis.lrangeBuffer("list:key", 0, -1); // Returns Buffer[]
```

## String Commands

Operations on Redis string data type (binary-safe).

```typescript { .api }
// Basic string operations
get(key: RedisKey): Promise<string | null>;
set(key: RedisKey, value: RedisValue): Promise<"OK">;
getset(key: RedisKey, value: RedisValue): Promise<string | null>;
append(key: RedisKey, value: RedisValue): Promise<number>;
strlen(key: RedisKey): Promise<number>;

// Multi-key operations
mget(...keys: RedisKey[]): Promise<Array<string | null>>;
mset(...args: Array<RedisKey | RedisValue>): Promise<"OK">;
msetnx(...args: Array<RedisKey | RedisValue>): Promise<number>;

// Numeric operations
incr(key: RedisKey): Promise<number>;
incrby(key: RedisKey, increment: number): Promise<number>;
incrbyfloat(key: RedisKey, increment: number): Promise<string>;
decr(key: RedisKey): Promise<number>;
decrby(key: RedisKey, decrement: number): Promise<number>;

// Substring operations
getrange(key: RedisKey, start: number, end: number): Promise<string>;
setrange(key: RedisKey, offset: number, value: RedisValue): Promise<number>;

// Bit operations
getbit(key: RedisKey, offset: number): Promise<number>;
setbit(key: RedisKey, offset: number, value: number): Promise<number>;
bitcount(key: RedisKey): Promise<number>;
bitcount(key: RedisKey, start: number, end: number): Promise<number>;
```

**Usage Examples:**

```typescript
// Basic string operations
await redis.set("user:name", "Alice");
const name = await redis.get("user:name");

// Expiration
await redis.set("session", "abc123", "EX", 3600); // Expire in 1 hour

// Multi-key operations
await redis.mset("key1", "value1", "key2", "value2");
const values = await redis.mget("key1", "key2");

// Numeric operations
await redis.set("counter", "0");
const count = await redis.incr("counter");
await redis.incrby("counter", 10);

// Conditional operations
const wasSet = await redis.set("lock", "value", "NX", "EX", 30);
if (wasSet) console.log("Lock acquired");
```

## Hash Commands

Operations on Redis hash data type (field-value maps).

```typescript { .api }
// Basic hash operations
hget(key: RedisKey, field: string): Promise<string | null>;
hset(key: RedisKey, field: string, value: RedisValue): Promise<number>;
hset(key: RedisKey, object: Record<string, RedisValue>): Promise<number>;
hdel(key: RedisKey, ...fields: string[]): Promise<number>;
hexists(key: RedisKey, field: string): Promise<number>;
hlen(key: RedisKey): Promise<number>;

// Multi-field operations
hmget(key: RedisKey, ...fields: string[]): Promise<Array<string | null>>;
hmset(key: RedisKey, ...args: Array<string | RedisValue>): Promise<"OK">;
hgetall(key: RedisKey): Promise<Record<string, string>>;
hkeys(key: RedisKey): Promise<string[]>;
hvals(key: RedisKey): Promise<string[]>;

// Numeric operations
hincrby(key: RedisKey, field: string, increment: number): Promise<number>;
hincrbyfloat(key: RedisKey, field: string, increment: number): Promise<string>;

// Conditional operations
hsetnx(key: RedisKey, field: string, value: RedisValue): Promise<number>;
```

**Usage Examples:**

```typescript
// Basic hash operations
await redis.hset("user:123", "name", "Alice");
await redis.hset("user:123", "email", "alice@example.com");
const name = await redis.hget("user:123", "name");

// Object-style setting
await redis.hset("user:456", {
  name: "Bob",
  email: "bob@example.com",
  age: "25"
});

// Get all hash data
const user = await redis.hgetall("user:123");
console.log(user); // { name: "Alice", email: "alice@example.com" }

// Multi-field operations  
const [name2, email] = await redis.hmget("user:123", "name", "email");

// Numeric operations
await redis.hincrby("stats:views", "page1", 1);
```

## List Commands

Operations on Redis list data type (linked lists).

```typescript { .api }
// Push operations
lpush(key: RedisKey, ...values: RedisValue[]): Promise<number>;
rpush(key: RedisKey, ...values: RedisValue[]): Promise<number>;
lpushx(key: RedisKey, ...values: RedisValue[]): Promise<number>;
rpushx(key: RedisKey, ...values: RedisValue[]): Promise<number>;

// Pop operations
lpop(key: RedisKey): Promise<string | null>;
rpop(key: RedisKey): Promise<string | null>;
blpop(...args: [...keys: RedisKey[], timeout: number]): Promise<[string, string] | null>;
brpop(...args: [...keys: RedisKey[], timeout: number]): Promise<[string, string] | null>;

// Range operations
lrange(key: RedisKey, start: number, stop: number): Promise<string[]>;
ltrim(key: RedisKey, start: number, stop: number): Promise<"OK">;

// Index operations
lindex(key: RedisKey, index: number): Promise<string | null>;
lset(key: RedisKey, index: number, value: RedisValue): Promise<"OK">;
linsert(key: RedisKey, direction: "BEFORE" | "AFTER", pivot: RedisValue, value: RedisValue): Promise<number>;

// List information
llen(key: RedisKey): Promise<number>;
lrem(key: RedisKey, count: number, value: RedisValue): Promise<number>;

// Blocking operations
brpoplpush(source: RedisKey, destination: RedisKey, timeout: number): Promise<string | null>;
```

**Usage Examples:**

```typescript
// Queue operations (FIFO)
await redis.lpush("queue", "job1", "job2", "job3");
const job = await redis.rpop("queue");

// Stack operations (LIFO)
await redis.lpush("stack", "item1", "item2");
const item = await redis.lpop("stack");

// Blocking operations
const result = await redis.blpop("queue", 10); // Wait 10 seconds
if (result) {
  const [queueName, value] = result;
  console.log(`Got ${value} from ${queueName}`);
}

// Range operations
await redis.rpush("messages", "msg1", "msg2", "msg3");
const messages = await redis.lrange("messages", 0, -1); // Get all
const recent = await redis.lrange("messages", -5, -1);  // Last 5
```

## Set Commands

Operations on Redis set data type (unordered collections).

```typescript { .api }
// Basic set operations
sadd(key: RedisKey, ...members: RedisValue[]): Promise<number>;
srem(key: RedisKey, ...members: RedisValue[]): Promise<number>;
smembers(key: RedisKey): Promise<string[]>;
scard(key: RedisKey): Promise<number>;
sismember(key: RedisKey, member: RedisValue): Promise<number>;

// Random operations
spop(key: RedisKey): Promise<string | null>;
spop(key: RedisKey, count: number): Promise<string[]>;
srandmember(key: RedisKey): Promise<string | null>;
srandmember(key: RedisKey, count: number): Promise<string[]>;

// Set operations
sinter(...keys: RedisKey[]): Promise<string[]>;
sunion(...keys: RedisKey[]): Promise<string[]>;
sdiff(...keys: RedisKey[]): Promise<string[]>;
sinterstore(destination: RedisKey, ...keys: RedisKey[]): Promise<number>;
sunionstore(destination: RedisKey, ...keys: RedisKey[]): Promise<number>;
sdiffstore(destination: RedisKey, ...keys: RedisKey[]): Promise<number>;

// Move operations
smove(source: RedisKey, destination: RedisKey, member: RedisValue): Promise<number>;
```

**Usage Examples:**

```typescript
// Basic set operations
await redis.sadd("tags", "redis", "database", "cache");
const tags = await redis.smembers("tags");
const hasRedis = await redis.sismember("tags", "redis");

// Set operations
await redis.sadd("user:123:tags", "redis", "javascript");
await redis.sadd("user:456:tags", "redis", "python");

// Find common tags
const commonTags = await redis.sinter("user:123:tags", "user:456:tags");
console.log(commonTags); // ["redis"]

// Random selection
const randomTag = await redis.srandmember("tags");
const randomTags = await redis.srandmember("tags", 2);
```

## Sorted Set Commands

Operations on Redis sorted set data type (scored collections).

```typescript { .api }
// Basic sorted set operations
zadd(key: RedisKey, ...args: Array<number | string>): Promise<number>;
zrem(key: RedisKey, ...members: RedisValue[]): Promise<number>;
zcard(key: RedisKey): Promise<number>;
zcount(key: RedisKey, min: string, max: string): Promise<number>;

// Range operations
zrange(key: RedisKey, start: number, stop: number): Promise<string[]>;
zrange(key: RedisKey, start: number, stop: number, withScores: "WITHSCORES"): Promise<string[]>;
zrevrange(key: RedisKey, start: number, stop: number): Promise<string[]>;
zrangebyscore(key: RedisKey, min: string, max: string): Promise<string[]>;
zrevrangebyscore(key: RedisKey, max: string, min: string): Promise<string[]>;

// Score operations
zscore(key: RedisKey, member: RedisValue): Promise<string | null>;
zincrby(key: RedisKey, increment: number, member: RedisValue): Promise<string>;
zrank(key: RedisKey, member: RedisValue): Promise<number | null>;
zrevrank(key: RedisKey, member: RedisValue): Promise<number | null>;

// Lexicographical operations
zrangebylex(key: RedisKey, min: string, max: string): Promise<string[]>;
zrevrangebylex(key: RedisKey, max: string, min: string): Promise<string[]>;
zlexcount(key: RedisKey, min: string, max: string): Promise<number>;
```

**Usage Examples:**

```typescript
// Leaderboard example
await redis.zadd("leaderboard", 100, "alice", 85, "bob", 120, "charlie");

// Get top players
const topPlayers = await redis.zrevrange("leaderboard", 0, 2, "WITHSCORES");
console.log(topPlayers); // ["charlie", "120", "alice", "100", "bob", "85"]

// Get player rank (0-based)
const aliceRank = await redis.zrevrank("leaderboard", "alice");
console.log(`Alice is rank ${aliceRank + 1}`);

// Update score
await redis.zincrby("leaderboard", 10, "bob");

// Range by score
const highScorers = await redis.zrangebyscore("leaderboard", "90", "+inf");
```

## Key Commands

Operations on Redis keys (metadata and lifecycle).

```typescript { .api }
// Key existence and information
exists(...keys: RedisKey[]): Promise<number>;
type(key: RedisKey): Promise<string>;
ttl(key: RedisKey): Promise<number>;
pttl(key: RedisKey): Promise<number>;

// Key expiration
expire(key: RedisKey, seconds: number): Promise<number>;
pexpire(key: RedisKey, milliseconds: number): Promise<number>;
expireat(key: RedisKey, timestamp: number): Promise<number>;
pexpireat(key: RedisKey, millisecondsTimestamp: number): Promise<number>;
persist(key: RedisKey): Promise<number>;

// Key operations
del(...keys: RedisKey[]): Promise<number>;
unlink(...keys: RedisKey[]): Promise<number>;
rename(key: RedisKey, newkey: RedisKey): Promise<"OK">;
renamenx(key: RedisKey, newkey: RedisKey): Promise<number>;
move(key: RedisKey, db: number): Promise<number>;

// Key scanning
keys(pattern: string): Promise<string[]>;
scan(cursor: string): Promise<[string, string[]]>;
scan(cursor: string, matchPattern: string): Promise<[string, string[]]>;
scan(cursor: string, countOption: "COUNT", count: number): Promise<[string, string[]]>;
```

**Usage Examples:**

```typescript
// Check key existence
const exists = await redis.exists("user:123");
if (exists) {
  const type = await redis.type("user:123");
  console.log(`Key exists and is of type: ${type}`);
}

// Set expiration
await redis.set("session:abc", "data");
await redis.expire("session:abc", 3600); // Expire in 1 hour

// Check TTL
const ttl = await redis.ttl("session:abc");
console.log(`Key expires in ${ttl} seconds`);

// Delete keys
await redis.del("old_key1", "old_key2");

// Pattern matching (use with caution on large datasets)
const userKeys = await redis.keys("user:*");

// Safer scanning for large datasets
let cursor = "0";
do {
  const [nextCursor, keys] = await redis.scan(cursor, "MATCH", "user:*", "COUNT", 100);
  cursor = nextCursor;
  console.log("Found keys:", keys);
} while (cursor !== "0");
```

## Types

```typescript { .api }
type RedisKey = string | Buffer;
type RedisValue = string | Buffer | number;
type Callback<T> = (err?: Error | null, result?: T) => void;
```